@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
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1826,22 +1826,28 @@ function isDateAfter(date, dateAfter) {
1826
1826
  */
1827
1827
  const getFormulaNumberRegex = memoize(function getFormulaNumberRegex(decimalSeparator) {
1828
1828
  decimalSeparator = escapeRegExp(decimalSeparator);
1829
- return new RegExp(`(^-?\\d+(${decimalSeparator}?\\d*(e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1829
+ return new RegExp(`(?:^-?\\d+(?:${decimalSeparator}?\\d*(?:e\\d+)?)?|^-?${decimalSeparator}\\d+)(?!\\w|!)`);
1830
1830
  });
1831
1831
  const getNumberRegex = memoize(function getNumberRegex(locale) {
1832
1832
  const decimalSeparator = escapeRegExp(locale.decimalSeparator);
1833
1833
  const thousandsSeparator = escapeRegExp(locale.thousandsSeparator);
1834
- const pIntegerAndDecimals = `(\\d+(${thousandsSeparator}\\d{3,})*(${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1835
- const pOnlyDecimals = `(${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1836
- const pScientificFormat = "(e(\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1837
- const pPercentFormat = "(\\s*%)?"; // pattern that match percent symbol between zero and one time
1838
- const pNumber = "(\\s*" + pIntegerAndDecimals + "|" + pOnlyDecimals + ")" + pScientificFormat + pPercentFormat;
1839
- const pMinus = "(\\s*-)?"; // pattern that match negative symbol between zero and one time
1840
- const pCurrencyFormat = "(\\s*[\\$€])?";
1834
+ const pIntegerAndDecimals = `(?:\\d+(?:${thousandsSeparator}\\d{3,})*(?:${decimalSeparator}\\d*)?)`; // pattern that match integer number with or without decimal digits
1835
+ const pOnlyDecimals = `(?:${decimalSeparator}\\d+)`; // pattern that match only expression with decimal digits
1836
+ const pScientificFormat = "(?:e(?:\\+|-)?\\d+)?"; // pattern that match scientific format between zero and one time (should be placed before pPercentFormat)
1837
+ const pPercentFormat = "(?:\\s*%)?"; // pattern that match percent symbol between zero and one time
1838
+ const pNumber = "(?:\\s*" +
1839
+ pIntegerAndDecimals +
1840
+ "|" +
1841
+ pOnlyDecimals +
1842
+ ")" +
1843
+ pScientificFormat +
1844
+ pPercentFormat;
1845
+ const pMinus = "(?:\\s*-)?"; // pattern that match negative symbol between zero and one time
1846
+ const pCurrencyFormat = "(?:\\s*[\\$€])?";
1841
1847
  const p1 = pMinus + pCurrencyFormat + pNumber;
1842
1848
  const p2 = pMinus + pNumber + pCurrencyFormat;
1843
1849
  const p3 = pCurrencyFormat + pMinus + pNumber;
1844
- const pNumberExp = "^((" + [p1, p2, p3].join(")|(") + "))$";
1850
+ const pNumberExp = "^(?:(?:" + [p1, p2, p3].join(")|(?:") + "))$";
1845
1851
  const numberRegexp = new RegExp(pNumberExp, "i");
1846
1852
  return numberRegexp;
1847
1853
  });
@@ -2779,7 +2785,7 @@ function evaluatePredicate(value, criterion) {
2779
2785
  return false;
2780
2786
  }
2781
2787
  if (typeof operand === "number" && operator === "=") {
2782
- return toString(value) === toString(operand);
2788
+ return value.toString() === operand.toString();
2783
2789
  }
2784
2790
  if (operator === "<>" || operator === "=") {
2785
2791
  let result;
@@ -2839,14 +2845,13 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2839
2845
  if (countArg % 2 === 1) {
2840
2846
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range and criterion to be in pairs."));
2841
2847
  }
2842
- const dimRow = args[0].length;
2843
- const dimCol = args[0][0].length;
2848
+ const firstArg = toMatrix(args[0]);
2849
+ const dimRow = firstArg.length;
2850
+ const dimCol = firstArg[0].length;
2844
2851
  let predicates = [];
2845
2852
  for (let i = 0; i < countArg - 1; i += 2) {
2846
- const criteriaRange = args[i];
2847
- if (!isMatrix(criteriaRange) ||
2848
- criteriaRange.length !== dimRow ||
2849
- criteriaRange[0].length !== dimCol) {
2853
+ const criteriaRange = toMatrix(args[i]);
2854
+ if (criteriaRange.length !== dimRow || criteriaRange[0].length !== dimCol) {
2850
2855
  throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects criteria_range to have the same dimension"));
2851
2856
  }
2852
2857
  const description = toString(args[i + 1]);
@@ -2860,7 +2865,7 @@ function visitMatchingRanges(args, cb, locale, isQuery = false) {
2860
2865
  for (let j = 0; j < dimCol; j++) {
2861
2866
  let validatedPredicates = true;
2862
2867
  for (let k = 0; k < countArg - 1; k += 2) {
2863
- const criteriaValue = args[k][i][j].value;
2868
+ const criteriaValue = toMatrix(args[k])[i][j].value;
2864
2869
  const criterion = predicates[k / 2];
2865
2870
  validatedPredicates = evaluatePredicate(criteriaValue ?? undefined, criterion);
2866
2871
  if (!validatedPredicates) {
@@ -3525,10 +3530,8 @@ function detectDateFormat(content, locale) {
3525
3530
  const internalDate = parseDateTime(content, locale);
3526
3531
  return internalDate.format;
3527
3532
  }
3533
+ /** use this function only if the content corresponds to a number (means that isNumber(content) return true */
3528
3534
  function detectNumberFormat(content) {
3529
- if (!isNumber(content, DEFAULT_LOCALE)) {
3530
- return undefined;
3531
- }
3532
3535
  const digitBase = content.includes(".") ? "0.00" : "0";
3533
3536
  const matchedCurrencies = content.match(/[\$€]/);
3534
3537
  if (matchedCurrencies) {
@@ -4731,21 +4734,16 @@ function unionPositionsToZone(positions) {
4731
4734
  * Check if two zones are contiguous, ie. that they share a border
4732
4735
  */
4733
4736
  function areZoneContiguous(zone1, zone2) {
4734
- const u = union(zone1, zone2);
4735
4737
  if (zone1.right + 1 === zone2.left || zone1.left === zone2.right + 1) {
4736
- return getZoneHeight(u) <= getZoneHeight(zone1) + getZoneHeight(zone2);
4738
+ return ((zone1.top <= zone2.bottom && zone1.top >= zone2.top) ||
4739
+ (zone2.top <= zone1.bottom && zone2.top >= zone1.top));
4737
4740
  }
4738
4741
  if (zone1.bottom + 1 === zone2.top || zone1.top === zone2.bottom + 1) {
4739
- return getZoneWidth(u) <= getZoneWidth(zone1) + getZoneWidth(zone2);
4742
+ return ((zone1.left <= zone2.right && zone1.left >= zone2.left) ||
4743
+ (zone2.left <= zone1.right && zone2.left >= zone1.left));
4740
4744
  }
4741
4745
  return false;
4742
4746
  }
4743
- function getZoneHeight(zone) {
4744
- return zone.bottom - zone.top + 1;
4745
- }
4746
- function getZoneWidth(zone) {
4747
- return zone.right - zone.left + 1;
4748
- }
4749
4747
  /**
4750
4748
  * Merge contiguous and overlapping zones that are in the array into bigger zones
4751
4749
  */
@@ -5284,7 +5282,7 @@ function clipTextWithEllipsis(ctx, text, maxWidth) {
5284
5282
  return text;
5285
5283
  }
5286
5284
  const ellipsis = "…";
5287
- const ellipsisWidth = computeCachedTextWidth(ctx, text);
5285
+ const ellipsisWidth = computeCachedTextWidth(ctx, ellipsis);
5288
5286
  if (width <= ellipsisWidth) {
5289
5287
  return text;
5290
5288
  }
@@ -5501,7 +5499,7 @@ class Registry {
5501
5499
  }
5502
5500
  }
5503
5501
 
5504
- function getClipboardDataPositions(zones) {
5502
+ function getClipboardDataPositions(sheetId, zones) {
5505
5503
  const lefts = new Set(zones.map((z) => z.left));
5506
5504
  const rights = new Set(zones.map((z) => z.right));
5507
5505
  const tops = new Set(zones.map((z) => z.top));
@@ -5515,7 +5513,7 @@ function getClipboardDataPositions(zones) {
5515
5513
  const cellsPosition = clippedZones.map((zone) => positions(zone)).flat();
5516
5514
  const columnsIndexes = [...new Set(cellsPosition.map((p) => p.col))].sort((a, b) => a - b);
5517
5515
  const rowsIndexes = [...new Set(cellsPosition.map((p) => p.row))].sort((a, b) => a - b);
5518
- return { zones, clippedZones, columnsIndexes, rowsIndexes };
5516
+ return { sheetId, zones, clippedZones, columnsIndexes, rowsIndexes };
5519
5517
  }
5520
5518
  /**
5521
5519
  * The clipped zone is copied as many times as it fits in the target.
@@ -5565,8 +5563,8 @@ class ClipboardHandler {
5565
5563
  isCutAllowed(data) {
5566
5564
  return "Success" /* CommandResult.Success */;
5567
5565
  }
5568
- getPasteTarget(target, content, options) {
5569
- return { zones: [] };
5566
+ getPasteTarget(sheetId, target, content, options) {
5567
+ return { zones: [], sheetId };
5570
5568
  }
5571
5569
  convertOSClipboardData(data) {
5572
5570
  return;
@@ -5604,7 +5602,7 @@ class AbstractCellClipboardHandler extends ClipboardHandler {
5604
5602
 
5605
5603
  class BorderClipboardHandler extends AbstractCellClipboardHandler {
5606
5604
  copy(data) {
5607
- const sheetId = this.getters.getActiveSheetId();
5605
+ const sheetId = data.sheetId;
5608
5606
  if (data.zones.length === 0) {
5609
5607
  return;
5610
5608
  }
@@ -5624,7 +5622,7 @@ class BorderClipboardHandler extends AbstractCellClipboardHandler {
5624
5622
  if (!content) {
5625
5623
  return;
5626
5624
  }
5627
- const sheetId = this.getters.getActiveSheetId();
5625
+ const sheetId = target.sheetId;
5628
5626
  if (options?.pasteOption === "asValue") {
5629
5627
  return;
5630
5628
  }
@@ -6154,7 +6152,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6154
6152
  if (!("zones" in data) || !data.zones.length) {
6155
6153
  return;
6156
6154
  }
6157
- const sheetId = this.getters.getActiveSheetId();
6155
+ const sheetId = data.sheetId;
6158
6156
  const zones = data.zones;
6159
6157
  if (!zones.length) {
6160
6158
  return {
@@ -6183,6 +6181,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6183
6181
  format: evaluatedCell.format,
6184
6182
  content,
6185
6183
  isFormula: false,
6184
+ parsedValue: evaluatedCell.value,
6186
6185
  };
6187
6186
  }
6188
6187
  cellsInRow.push({
@@ -6197,7 +6196,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6197
6196
  return {
6198
6197
  cells: clippedCells,
6199
6198
  zones: clippedZones,
6200
- sheetId: this.getters.getActiveSheetId(),
6199
+ sheetId: data.sheetId,
6201
6200
  };
6202
6201
  }
6203
6202
  isPasteAllowed(sheetId, target, content, clipboardOptions) {
@@ -6225,7 +6224,7 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6225
6224
  return;
6226
6225
  }
6227
6226
  const zones = target.zones;
6228
- const sheetId = this.getters.getActiveSheetId();
6227
+ const sheetId = target.sheetId;
6229
6228
  if (!options?.isCutOperation) {
6230
6229
  this.pasteFromCopy(sheetId, zones, content.cells, options);
6231
6230
  }
@@ -6233,11 +6232,12 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6233
6232
  this.pasteFromCut(sheetId, zones, content, options);
6234
6233
  }
6235
6234
  }
6236
- getPasteTarget(target, content, options) {
6235
+ getPasteTarget(sheetId, target, content, options) {
6237
6236
  const width = content.cells[0].length;
6238
6237
  const height = content.cells.length;
6239
6238
  if (options?.isCutOperation) {
6240
6239
  return {
6240
+ sheetId,
6241
6241
  zones: [
6242
6242
  {
6243
6243
  left: target[0].left,
@@ -6249,11 +6249,9 @@ class CellClipboardHandler extends AbstractCellClipboardHandler {
6249
6249
  };
6250
6250
  }
6251
6251
  if (width === 1 && height === 1) {
6252
- return { zones: [] };
6252
+ return { zones: [], sheetId };
6253
6253
  }
6254
- return {
6255
- zones: getPasteZones(target, content.cells),
6256
- };
6254
+ return { sheetId, zones: getPasteZones(target, content.cells) };
6257
6255
  }
6258
6256
  pasteFromCut(sheetId, target, content, options) {
6259
6257
  this.clearClippedZones(content);
@@ -6376,7 +6374,7 @@ class AbstractFigureClipboardHandler extends ClipboardHandler {
6376
6374
 
6377
6375
  class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6378
6376
  copy(data) {
6379
- const sheetId = this.getters.getActiveSheetId();
6377
+ const sheetId = data.sheetId;
6380
6378
  const figure = this.getters.getFigure(sheetId, data.figureId);
6381
6379
  if (!figure) {
6382
6380
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6396,22 +6394,19 @@ class ChartClipboardHandler extends AbstractFigureClipboardHandler {
6396
6394
  copiedChart,
6397
6395
  };
6398
6396
  }
6399
- getPasteTarget(target, content, options) {
6397
+ getPasteTarget(sheetId, target, content, options) {
6400
6398
  if (!content?.copiedFigure || !content?.copiedChart) {
6401
- return { zones: [] };
6399
+ return { zones: [], sheetId };
6402
6400
  }
6403
6401
  const newId = new UuidGenerator().uuidv4();
6404
- return {
6405
- zones: [],
6406
- figureId: newId,
6407
- };
6402
+ return { zones: [], figureId: newId, sheetId };
6408
6403
  }
6409
6404
  paste(target, clippedContent, options) {
6410
6405
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedChart || !target.figureId) {
6411
6406
  return;
6412
6407
  }
6413
6408
  const { zones, figureId } = target;
6414
- const sheetId = this.getters.getActiveSheetId();
6409
+ const sheetId = target.sheetId;
6415
6410
  const numCols = this.getters.getNumberCols(sheetId);
6416
6411
  const numRows = this.getters.getNumberRows(sheetId);
6417
6412
  const targetX = this.getters.getColDimensions(sheetId, zones[0].left).start;
@@ -6457,7 +6452,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6457
6452
  return;
6458
6453
  }
6459
6454
  const { rowsIndexes, columnsIndexes } = data;
6460
- const sheetId = this.getters.getActiveSheetId();
6455
+ const sheetId = data.sheetId;
6461
6456
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6462
6457
  return {
6463
6458
  cellPositions,
@@ -6471,7 +6466,7 @@ class ConditionalFormatClipboardHandler extends AbstractCellClipboardHandler {
6471
6466
  return;
6472
6467
  }
6473
6468
  const zones = target.zones;
6474
- const sheetId = this.getters.getActiveSheetId();
6469
+ const sheetId = target.sheetId;
6475
6470
  if (!options?.isCutOperation) {
6476
6471
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6477
6472
  }
@@ -6552,7 +6547,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6552
6547
  return;
6553
6548
  }
6554
6549
  const { rowsIndexes, columnsIndexes } = data;
6555
- const sheetId = this.getters.getActiveSheetId();
6550
+ const sheetId = data.sheetId;
6556
6551
  const cellPositions = rowsIndexes.map((row) => columnsIndexes.map((col) => ({ col, row, sheetId })));
6557
6552
  return {
6558
6553
  cellPositions,
@@ -6569,7 +6564,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6569
6564
  return;
6570
6565
  }
6571
6566
  const zones = target.zones;
6572
- const sheetId = this.getters.getActiveSheetId();
6567
+ const sheetId = target.sheetId;
6573
6568
  if (!options?.isCutOperation) {
6574
6569
  this.pasteFromCopy(sheetId, zones, clippedContent.cellPositions);
6575
6570
  }
@@ -6648,7 +6643,7 @@ class DataValidationClipboardHandler extends AbstractCellClipboardHandler {
6648
6643
 
6649
6644
  class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6650
6645
  copy(data) {
6651
- const sheetId = this.getters.getActiveSheetId();
6646
+ const sheetId = data.sheetId;
6652
6647
  const figure = this.getters.getFigure(sheetId, data.figureId);
6653
6648
  if (!figure) {
6654
6649
  throw new Error(`No figure for the given id: ${data.figureId}`);
@@ -6666,15 +6661,12 @@ class ImageClipboardHandler extends AbstractFigureClipboardHandler {
6666
6661
  sheetId,
6667
6662
  };
6668
6663
  }
6669
- getPasteTarget(target, content, options) {
6664
+ getPasteTarget(sheetId, target, content, options) {
6670
6665
  if (!content?.copiedFigure || !content?.copiedImage) {
6671
- return { zones: [] };
6666
+ return { zones: [], sheetId };
6672
6667
  }
6673
6668
  const newId = new UuidGenerator().uuidv4();
6674
- return {
6675
- zones: [],
6676
- figureId: newId,
6677
- };
6669
+ return { sheetId, zones: [], figureId: newId };
6678
6670
  }
6679
6671
  paste(target, clippedContent, options) {
6680
6672
  if (!clippedContent?.copiedFigure || !clippedContent?.copiedImage || !target.figureId) {
@@ -6745,8 +6737,7 @@ class MergeClipboardHandler extends AbstractCellClipboardHandler {
6745
6737
  if (options?.isCutOperation || !("zones" in target) || !target.zones.length) {
6746
6738
  return;
6747
6739
  }
6748
- const sheetId = this.getters.getActiveSheetId();
6749
- this.pasteFromCopy(sheetId, target.zones, content.cells, options);
6740
+ this.pasteFromCopy(target.sheetId, target.zones, content.cells, options);
6750
6741
  }
6751
6742
  pasteZone(sheetId, col, row, cells) {
6752
6743
  for (const [r, rowCells] of cells.entries()) {
@@ -6806,7 +6797,7 @@ class SheetClipboardHandler extends AbstractCellClipboardHandler {
6806
6797
 
6807
6798
  class TableClipboardHandler extends AbstractCellClipboardHandler {
6808
6799
  copy(data) {
6809
- const sheetId = this.getters.getActiveSheetId();
6800
+ const sheetId = data.sheetId;
6810
6801
  const { rowsIndexes, columnsIndexes, zones } = data;
6811
6802
  if (!zones || !rowsIndexes.length || !columnsIndexes.length) {
6812
6803
  return { tableCells: [[]], sheetId };
@@ -6848,7 +6839,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6848
6839
  }
6849
6840
  return {
6850
6841
  tableCells,
6851
- sheetId: this.getters.getActiveSheetId(),
6842
+ sheetId: data.sheetId,
6852
6843
  };
6853
6844
  }
6854
6845
  /**
@@ -6870,7 +6861,7 @@ class TableClipboardHandler extends AbstractCellClipboardHandler {
6870
6861
  return;
6871
6862
  }
6872
6863
  const zones = target.zones;
6873
- const sheetId = this.getters.getActiveSheetId();
6864
+ const sheetId = target.sheetId;
6874
6865
  if (!options?.isCutOperation) {
6875
6866
  this.pasteFromCopy(sheetId, zones, content.tableCells, options);
6876
6867
  }
@@ -7632,10 +7623,8 @@ function detectLink(value) {
7632
7623
  return undefined;
7633
7624
  }
7634
7625
 
7635
- function evaluateLiteral(content = "", localeFormat) {
7636
- const value = localeFormat.format === PLAIN_TEXT_FORMAT
7637
- ? content
7638
- : parseLiteral(content, localeFormat.locale);
7626
+ function evaluateLiteral(literalCell, localeFormat) {
7627
+ const value = localeFormat.format === PLAIN_TEXT_FORMAT ? literalCell.content : literalCell.parsedValue;
7639
7628
  const fPayload = { value, format: localeFormat.format };
7640
7629
  return createEvaluatedCell(fPayload, localeFormat.locale);
7641
7630
  }
@@ -7647,10 +7636,11 @@ function parseLiteral(content, locale) {
7647
7636
  return null;
7648
7637
  }
7649
7638
  if (isNumber(content, DEFAULT_LOCALE)) {
7650
- return toNumber(content, DEFAULT_LOCALE);
7639
+ return parseNumber(content, DEFAULT_LOCALE);
7651
7640
  }
7652
- if (isDateTime(content, locale)) {
7653
- return toNumber(content, locale);
7641
+ const internalDate = parseDateTime(content, locale);
7642
+ if (internalDate) {
7643
+ return internalDate.value;
7654
7644
  }
7655
7645
  if (isBoolean(content)) {
7656
7646
  return content.toUpperCase() === "TRUE" ? true : false;
@@ -7662,9 +7652,14 @@ function createEvaluatedCell(fPayload, locale = DEFAULT_LOCALE, cell) {
7662
7652
  if (!link) {
7663
7653
  return _createEvaluatedCell(fPayload, locale, cell);
7664
7654
  }
7655
+ const value = parseLiteral(link.label, locale);
7656
+ const format = fPayload.format ||
7657
+ (typeof value === "number"
7658
+ ? detectDateFormat(link.label, locale) || detectNumberFormat(link.label)
7659
+ : undefined);
7665
7660
  const linkPayload = {
7666
- value: parseLiteral(link.label, locale),
7667
- format: fPayload.format || detectDateFormat(link.label, locale) || detectNumberFormat(link.label),
7661
+ value,
7662
+ format,
7668
7663
  };
7669
7664
  return {
7670
7665
  ..._createEvaluatedCell(linkPayload, locale, cell),
@@ -10427,6 +10422,7 @@ let ScorecardChart$1 = class ScorecardChart extends AbstractChart {
10427
10422
  function drawScoreChart(structure, canvas) {
10428
10423
  const ctx = canvas.getContext("2d");
10429
10424
  canvas.width = structure.canvas.width;
10425
+ const availableWidth = canvas.width - DEFAULT_CHART_PADDING;
10430
10426
  canvas.height = structure.canvas.height;
10431
10427
  ctx.fillStyle = structure.canvas.backgroundColor;
10432
10428
  ctx.fillRect(0, 0, structure.canvas.width, structure.canvas.height);
@@ -10435,7 +10431,7 @@ function drawScoreChart(structure, canvas) {
10435
10431
  ctx.fillStyle = structure.title.style.color;
10436
10432
  const baseline = ctx.textBaseline;
10437
10433
  ctx.textBaseline = "middle";
10438
- ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, canvas.width - structure.title.position.x), structure.title.position.x, structure.title.position.y);
10434
+ ctx.fillText(clipTextWithEllipsis(ctx, structure.title.text, availableWidth - structure.title.position.x), structure.title.position.x, structure.title.position.y);
10439
10435
  ctx.textBaseline = baseline;
10440
10436
  }
10441
10437
  if (structure.baseline) {
@@ -10525,13 +10521,16 @@ function createScorecardChartRuntime(chart, getters) {
10525
10521
  return {
10526
10522
  title: {
10527
10523
  ...chart.title,
10524
+ // chart titles are extracted from .json files and they are translated at runtime here
10528
10525
  text: _t(chart.title.text ?? ""),
10529
10526
  },
10530
10527
  keyValue: formattedKeyValue,
10531
10528
  baselineDisplay,
10532
10529
  baselineArrow: getBaselineArrowDirection(baselineCell, keyValueCell, chart.baselineMode),
10533
10530
  baselineColor: getBaselineColor(baselineCell, chart.baselineMode, keyValueCell, chart.baselineColorUp, chart.baselineColorDown),
10534
- baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr ? _t(chart.baselineDescr) : "",
10531
+ baselineDescr: chart.baselineMode !== "progress" && chart.baselineDescr
10532
+ ? _t(chart.baselineDescr) // descriptions are extracted from .json files and they are translated at runtime here
10533
+ : "",
10535
10534
  fontColor,
10536
10535
  background,
10537
10536
  baselineStyle: chart.baselineMode !== "percentage" && chart.baselineMode !== "progress" && baseline
@@ -10560,7 +10559,7 @@ function createScorecardChartRuntime(chart, getters) {
10560
10559
  /* Sizes of boxes containing the texts, in percentage of the Chart size */
10561
10560
  const KEY_BOX_HEIGHT_RATIO = 0.8;
10562
10561
  /* Padding at the border of the chart */
10563
- const CHART_PADDING = DEFAULT_CHART_PADDING;
10562
+ const CHART_PADDING = 10;
10564
10563
  const BOTTOM_PADDING_RATIO = 0.05;
10565
10564
  /**
10566
10565
  * Line height (in em)
@@ -10710,6 +10709,7 @@ class ScorecardChartConfigBuilder {
10710
10709
  position: {
10711
10710
  x: (this.width - keyWidth) / 2,
10712
10711
  y: this.height * (0.5 - BOTTOM_PADDING_RATIO * 2) +
10712
+ CHART_PADDING / 2 +
10713
10713
  (titleHeight + keyHeight / (this.baseline || this.baselineDescr ? 2 : 1.2)) / 2,
10714
10714
  },
10715
10715
  };
@@ -10769,7 +10769,8 @@ class ScorecardChartConfigBuilder {
10769
10769
  const remainingWidth = maxLineWidth - baselineValueWidth;
10770
10770
  let baselineDescrFontSize = getFontSizeMatchingWidth(remainingWidth, baselineValueFontSize, (fontSize) => computeTextWidth(this.context, this.baselineDescr, { fontSize }));
10771
10771
  let isBaselineSplit = false;
10772
- if (baselineDescrFontSize < baselineValueFontSize / 2.5) {
10772
+ if (baselineDescrFontSize < baselineValueFontSize / 2.5 &&
10773
+ this.baselineDescr.trim().includes(" ")) {
10773
10774
  isBaselineSplit = true;
10774
10775
  baselineDescrFontSize = Math.floor(baselineValueFontSize / 2.5);
10775
10776
  for (const line of splitTextInTwoLines(this.baselineDescr)) {
@@ -10818,7 +10819,7 @@ class ScorecardChartConfigBuilder {
10818
10819
  /** Get the height of the chart minus all the vertical paddings */
10819
10820
  getDrawableHeight() {
10820
10821
  const verticalPadding = CHART_PADDING + this.height * BOTTOM_PADDING_RATIO;
10821
- let availableHeight = this.height - 2 * verticalPadding;
10822
+ let availableHeight = this.height - verticalPadding;
10822
10823
  availableHeight -= this.title ? DEFAULT_CHART_FONT_SIZE * LINE_HEIGHT : 0;
10823
10824
  return availableHeight;
10824
10825
  }
@@ -10860,6 +10861,11 @@ class ScorecardChart extends Component {
10860
10861
  get runtime() {
10861
10862
  return this.env.model.getters.getChartRuntime(this.props.figure.id);
10862
10863
  }
10864
+ get title() {
10865
+ const title = this.env.model.getters.getChartDefinition(this.props.figure.id).title.text ?? "";
10866
+ // chart titles are extracted from .json files and they are translated at runtime here
10867
+ return _t(title);
10868
+ }
10863
10869
  setup() {
10864
10870
  useEffect(this.createChart.bind(this), () => {
10865
10871
  const canvas = this.canvas.el;
@@ -10988,6 +10994,9 @@ function makeArg(str, description) {
10988
10994
  if (types.some((t) => t.startsWith("RANGE"))) {
10989
10995
  result.acceptMatrix = true;
10990
10996
  }
10997
+ if (types.every((t) => t.startsWith("RANGE"))) {
10998
+ result.acceptMatrixOnly = true;
10999
+ }
10991
11000
  return result;
10992
11001
  }
10993
11002
  /**
@@ -11242,7 +11251,6 @@ const ARRAY_CONSTRAIN = {
11242
11251
  arg("rows (number)", _t("The number of rows in the constrained array.")),
11243
11252
  arg("columns (number)", _t("The number of columns in the constrained array.")),
11244
11253
  ],
11245
- returns: ["RANGE<ANY>"],
11246
11254
  compute: function (array, rows, columns) {
11247
11255
  const _array = toMatrix(array);
11248
11256
  const _rowsArg = toInteger(rows?.value, this.locale);
@@ -11265,15 +11273,19 @@ const CHOOSECOLS = {
11265
11273
  arg("col_num (number, range<number>)", _t("The first column index of the columns to be returned.")),
11266
11274
  arg("col_num2 (number, range<number>, repeating)", _t("The columns indexes of the columns to be returned.")),
11267
11275
  ],
11268
- returns: ["RANGE<ANY>"],
11269
11276
  compute: function (array, ...columns) {
11270
11277
  const _array = toMatrix(array);
11271
11278
  const _columns = flattenRowFirst(columns, (item) => toInteger(item?.value, this.locale));
11272
- 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()));
11279
+ const argOutOfRange = _columns.filter((col) => col === 0 || _array.length < Math.abs(col));
11280
+ 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(",")));
11273
11281
  const result = Array(_columns.length);
11274
11282
  for (let col = 0; col < _columns.length; col++) {
11275
- const colIndex = _columns[col] - 1; // -1 because columns arguments are 1-indexed
11276
- result[col] = _array[colIndex];
11283
+ if (_columns[col] > 0) {
11284
+ result[col] = _array[_columns[col] - 1]; // -1 because columns arguments are 1-indexed
11285
+ }
11286
+ else {
11287
+ result[col] = _array[_array.length + _columns[col]];
11288
+ }
11277
11289
  }
11278
11290
  return result;
11279
11291
  },
@@ -11289,13 +11301,18 @@ const CHOOSEROWS = {
11289
11301
  arg("row_num (number, range<number>)", _t("The first row index of the rows to be returned.")),
11290
11302
  arg("row_num2 (number, range<number>, repeating)", _t("The rows indexes of the rows to be returned.")),
11291
11303
  ],
11292
- returns: ["RANGE<ANY>"],
11293
11304
  compute: function (array, ...rows) {
11294
11305
  const _array = toMatrix(array);
11295
11306
  const _rows = flattenRowFirst(rows, (item) => toInteger(item?.value, this.locale));
11296
11307
  const _nbColumns = _array.length;
11297
- 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()));
11298
- return generateMatrix(_nbColumns, _rows.length, (col, row) => _array[col][_rows[row] - 1]); // -1 because rows arguments are 1-indexed
11308
+ const argOutOfRange = _rows.filter((row) => row === 0 || _array[0].length < Math.abs(row));
11309
+ 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(",")));
11310
+ return generateMatrix(_nbColumns, _rows.length, (col, row) => {
11311
+ if (_rows[row] > 0) {
11312
+ return _array[col][_rows[row] - 1]; // -1 because columns arguments are 1-indexed
11313
+ }
11314
+ return _array[col][_array[col].length + _rows[row]];
11315
+ });
11299
11316
  },
11300
11317
  isExported: true,
11301
11318
  };
@@ -11310,7 +11327,6 @@ const EXPAND = {
11310
11327
  arg("columns (number, optional)", _t("The number of columns in the expanded array. If missing, columns will not be expanded.")),
11311
11328
  arg("pad_with (any, default=0)", _t("The value with which to pad.")), // @compatibility: on Excel, pad with #N/A
11312
11329
  ],
11313
- returns: ["RANGE<ANY>"],
11314
11330
  compute: function (arg, rows, columns, padWith = { value: 0 } // TODO : Replace with #N/A errors once it's supported
11315
11331
  ) {
11316
11332
  const _array = toMatrix(arg);
@@ -11331,7 +11347,6 @@ const FLATTEN = {
11331
11347
  arg("range (any, range<any>)", _t("The first range to flatten.")),
11332
11348
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to flatten.")),
11333
11349
  ],
11334
- returns: ["RANGE<ANY>"],
11335
11350
  compute: function (...ranges) {
11336
11351
  return [flattenRowFirst(ranges, (val) => (val === undefined ? { value: "" } : val))];
11337
11352
  },
@@ -11346,7 +11361,6 @@ const FREQUENCY = {
11346
11361
  arg("data (range<number>)", _t("The array of ranges containing the values to be counted.")),
11347
11362
  arg("classes (number, range<number>)", _t("The range containing the set of classes.")),
11348
11363
  ],
11349
- returns: ["RANGE<NUMBER>"],
11350
11364
  compute: function (data, classes) {
11351
11365
  const _data = flattenRowFirst([data], (data) => data.value).filter((val) => typeof val === "number");
11352
11366
  const _classes = flattenRowFirst([classes], (data) => data.value).filter((val) => typeof val === "number");
@@ -11394,7 +11408,6 @@ const HSTACK = {
11394
11408
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11395
11409
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11396
11410
  ],
11397
- returns: ["RANGE<ANY>"],
11398
11411
  compute: function (...ranges) {
11399
11412
  const nbRows = Math.max(...ranges.map((r) => r?.[0]?.length ?? 0));
11400
11413
  const result = [];
@@ -11421,7 +11434,6 @@ const MDETERM = {
11421
11434
  args: [
11422
11435
  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.")),
11423
11436
  ],
11424
- returns: ["NUMBER"],
11425
11437
  compute: function (matrix) {
11426
11438
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11427
11439
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11437,7 +11449,6 @@ const MINVERSE = {
11437
11449
  args: [
11438
11450
  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.")),
11439
11451
  ],
11440
- returns: ["RANGE<NUMBER>"],
11441
11452
  compute: function (matrix) {
11442
11453
  const _matrix = toNumberMatrix(matrix, "square_matrix");
11443
11454
  assertSquareMatrix(_t("The argument square_matrix must have the same number of columns and rows."), _matrix);
@@ -11458,7 +11469,6 @@ const MMULT = {
11458
11469
  arg("matrix1 (number, range<number>)", _t("The first matrix in the matrix multiplication operation.")),
11459
11470
  arg("matrix2 (number, range<number>)", _t("The second matrix in the matrix multiplication operation.")),
11460
11471
  ],
11461
- returns: ["RANGE<NUMBER>"],
11462
11472
  compute: function (matrix1, matrix2) {
11463
11473
  const _matrix1 = toNumberMatrix(matrix1, "matrix1");
11464
11474
  const _matrix2 = toNumberMatrix(matrix2, "matrix2");
@@ -11477,7 +11487,6 @@ const SUMPRODUCT = {
11477
11487
  arg("range1 (number, range<number>)", _t("The first range whose entries will be multiplied with corresponding entries in the other ranges.")),
11478
11488
  arg("range2 (number, range<number>, repeating)", _t("The other range whose entries will be multiplied with corresponding entries in the other ranges.")),
11479
11489
  ],
11480
- returns: ["NUMBER"],
11481
11490
  compute: function (...args) {
11482
11491
  assertSameDimensions(_t("All the ranges must have the same dimensions."), ...args);
11483
11492
  const _args = args.map(toMatrix);
@@ -11534,7 +11543,6 @@ const SUMX2MY2 = {
11534
11543
  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.")),
11535
11544
  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.")),
11536
11545
  ],
11537
- returns: ["NUMBER"],
11538
11546
  compute: function (arrayX, arrayY) {
11539
11547
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 - y ** 2);
11540
11548
  },
@@ -11549,7 +11557,6 @@ const SUMX2PY2 = {
11549
11557
  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.")),
11550
11558
  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.")),
11551
11559
  ],
11552
- returns: ["NUMBER"],
11553
11560
  compute: function (arrayX, arrayY) {
11554
11561
  return getSumXAndY(arrayX, arrayY, (x, y) => x ** 2 + y ** 2);
11555
11562
  },
@@ -11564,7 +11571,6 @@ const SUMXMY2 = {
11564
11571
  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.")),
11565
11572
  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.")),
11566
11573
  ],
11567
- returns: ["NUMBER"],
11568
11574
  compute: function (arrayX, arrayY) {
11569
11575
  return getSumXAndY(arrayX, arrayY, (x, y) => (x - y) ** 2);
11570
11576
  },
@@ -11600,7 +11606,6 @@ function shouldKeepValue(ignore) {
11600
11606
  const TOCOL = {
11601
11607
  description: _t("Transforms a range of cells into a single column."),
11602
11608
  args: TO_COL_ROW_ARGS,
11603
- returns: ["RANGE<ANY>"],
11604
11609
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11605
11610
  const _array = toMatrix(array);
11606
11611
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11621,7 +11626,6 @@ const TOCOL = {
11621
11626
  const TOROW = {
11622
11627
  description: _t("Transforms a range of cells into a single row."),
11623
11628
  args: TO_COL_ROW_ARGS,
11624
- returns: ["RANGE<ANY>"],
11625
11629
  compute: function (array, ignore = { value: TO_COL_ROW_DEFAULT_IGNORE }, scanByColumn = { value: TO_COL_ROW_DEFAULT_SCAN }) {
11626
11630
  const _array = toMatrix(array);
11627
11631
  const _ignore = toNumber(ignore.value, this.locale);
@@ -11643,7 +11647,6 @@ const TOROW = {
11643
11647
  const TRANSPOSE = {
11644
11648
  description: _t("Transposes the rows and columns of a range."),
11645
11649
  args: [arg("range (any, range<any>)", _t("The range to be transposed."))],
11646
- returns: ["RANGE"],
11647
11650
  compute: function (arg) {
11648
11651
  const _array = toMatrix(arg);
11649
11652
  const nbColumns = _array[0].length;
@@ -11661,7 +11664,6 @@ const VSTACK = {
11661
11664
  arg("range1 (any, range<any>)", _t("The first range to be appended.")),
11662
11665
  arg("range2 (any, range<any>, repeating)", _t("Additional ranges to add to range1.")),
11663
11666
  ],
11664
- returns: ["RANGE<ANY>"],
11665
11667
  compute: function (...ranges) {
11666
11668
  const nbColumns = Math.max(...ranges.map((range) => toMatrix(range).length));
11667
11669
  const nbRows = ranges.reduce((acc, range) => acc + toMatrix(range)[0].length, 0);
@@ -11693,7 +11695,6 @@ const WRAPCOLS = {
11693
11695
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11694
11696
  _t("The value with which to fill the extra cells in the range.")),
11695
11697
  ],
11696
- returns: ["RANGE<ANY>"],
11697
11698
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11698
11699
  const _array = toMatrix(range);
11699
11700
  const nbRows = toInteger(wrapCount?.value, this.locale);
@@ -11718,7 +11719,6 @@ const WRAPROWS = {
11718
11719
  arg("pad_with (any, default=0)", // TODO : replace with #N/A
11719
11720
  _t("The value with which to fill the extra cells in the range.")),
11720
11721
  ],
11721
- returns: ["RANGE<ANY>"],
11722
11722
  compute: function (range, wrapCount, padWith = { value: 0 }) {
11723
11723
  const _array = toMatrix(range);
11724
11724
  const nbColumns = toInteger(wrapCount?.value, this.locale);
@@ -11766,7 +11766,6 @@ const FORMAT_LARGE_NUMBER = {
11766
11766
  arg("value (number)", _t("The number.")),
11767
11767
  arg("unit (string, optional)", _t("The formatting unit. Use 'k', 'm', or 'b' to force the unit")),
11768
11768
  ],
11769
- returns: ["NUMBER"],
11770
11769
  compute: function (value, unite) {
11771
11770
  return {
11772
11771
  value: toNumber(value, this.locale),
@@ -11798,7 +11797,6 @@ const DECIMAL_REPRESENTATION = /^-?[a-z0-9]+$/i;
11798
11797
  const ABS = {
11799
11798
  description: _t("Absolute value of a number."),
11800
11799
  args: [arg("value (number)", _t("The number of which to return the absolute value."))],
11801
- returns: ["NUMBER"],
11802
11800
  compute: function (value) {
11803
11801
  return Math.abs(toNumber(value, this.locale));
11804
11802
  },
@@ -11812,7 +11810,6 @@ const ACOS = {
11812
11810
  args: [
11813
11811
  arg("value (number)", _t("The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.")),
11814
11812
  ],
11815
- returns: ["NUMBER"],
11816
11813
  compute: function (value) {
11817
11814
  const _value = toNumber(value, this.locale);
11818
11815
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11828,7 +11825,6 @@ const ACOSH = {
11828
11825
  args: [
11829
11826
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cosine. Must be greater than or equal to 1.")),
11830
11827
  ],
11831
- returns: ["NUMBER"],
11832
11828
  compute: function (value) {
11833
11829
  const _value = toNumber(value, this.locale);
11834
11830
  assert(() => _value >= 1, _t("The value (%s) must be greater than or equal to 1.", _value.toString()));
@@ -11842,7 +11838,6 @@ const ACOSH = {
11842
11838
  const ACOT = {
11843
11839
  description: _t("Inverse cotangent of a value."),
11844
11840
  args: [arg("value (number)", _t("The value for which to calculate the inverse cotangent."))],
11845
- returns: ["NUMBER"],
11846
11841
  compute: function (value) {
11847
11842
  const _value = toNumber(value, this.locale);
11848
11843
  const sign = Math.sign(_value) || 1;
@@ -11861,7 +11856,6 @@ const ACOTH = {
11861
11856
  args: [
11862
11857
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic cotangent. Must not be between -1 and 1, inclusive.")),
11863
11858
  ],
11864
- returns: ["NUMBER"],
11865
11859
  compute: function (value) {
11866
11860
  const _value = toNumber(value, this.locale);
11867
11861
  assert(() => Math.abs(_value) > 1, _t("The value (%s) cannot be between -1 and 1 inclusive.", _value.toString()));
@@ -11877,7 +11871,6 @@ const ASIN = {
11877
11871
  args: [
11878
11872
  arg("value (number)", _t("The value for which to calculate the inverse sine. Must be between -1 and 1, inclusive.")),
11879
11873
  ],
11880
- returns: ["NUMBER"],
11881
11874
  compute: function (value) {
11882
11875
  const _value = toNumber(value, this.locale);
11883
11876
  assert(() => Math.abs(_value) <= 1, _t("The value (%s) must be between -1 and 1 inclusive.", _value.toString()));
@@ -11893,7 +11886,6 @@ const ASINH = {
11893
11886
  args: [
11894
11887
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic sine.")),
11895
11888
  ],
11896
- returns: ["NUMBER"],
11897
11889
  compute: function (value) {
11898
11890
  return Math.asinh(toNumber(value, this.locale));
11899
11891
  },
@@ -11905,7 +11897,6 @@ const ASINH = {
11905
11897
  const ATAN = {
11906
11898
  description: _t("Inverse tangent of a value, in radians."),
11907
11899
  args: [arg("value (number)", _t("The value for which to calculate the inverse tangent."))],
11908
- returns: ["NUMBER"],
11909
11900
  compute: function (value) {
11910
11901
  return Math.atan(toNumber(value, this.locale));
11911
11902
  },
@@ -11920,7 +11911,6 @@ const ATAN2 = {
11920
11911
  arg("x (number)", _t("The x coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11921
11912
  arg("y (number)", _t("The y coordinate of the endpoint of the line segment for which to calculate the angle from the x-axis.")),
11922
11913
  ],
11923
- returns: ["NUMBER"],
11924
11914
  compute: function (x, y) {
11925
11915
  const _x = toNumber(x, this.locale);
11926
11916
  const _y = toNumber(y, this.locale);
@@ -11937,7 +11927,6 @@ const ATANH = {
11937
11927
  args: [
11938
11928
  arg("value (number)", _t("The value for which to calculate the inverse hyperbolic tangent. Must be between -1 and 1, exclusive.")),
11939
11929
  ],
11940
- returns: ["NUMBER"],
11941
11930
  compute: function (value) {
11942
11931
  const _value = toNumber(value, this.locale);
11943
11932
  assert(() => Math.abs(_value) < 1, _t("The value (%s) must be between -1 and 1 exclusive.", _value.toString()));
@@ -11954,7 +11943,6 @@ const CEILING = {
11954
11943
  arg("value (number)", _t("The value to round up to the nearest integer multiple of factor.")),
11955
11944
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
11956
11945
  ],
11957
- returns: ["NUMBER"],
11958
11946
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
11959
11947
  const _value = toNumber(value, this.locale);
11960
11948
  const _factor = toNumber(factor, this.locale);
@@ -11989,7 +11977,6 @@ const CEILING_MATH = {
11989
11977
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
11990
11978
  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.")),
11991
11979
  ],
11992
- returns: ["NUMBER"],
11993
11980
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
11994
11981
  const _significance = toNumber(significance, this.locale);
11995
11982
  const _number = toNumber(number, this.locale);
@@ -12010,7 +11997,6 @@ const CEILING_PRECISE = {
12010
11997
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12011
11998
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12012
11999
  ],
12013
- returns: ["NUMBER"],
12014
12000
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12015
12001
  const _significance = toNumber(significance, this.locale);
12016
12002
  const _number = toNumber(number, this.locale);
@@ -12027,7 +12013,6 @@ const CEILING_PRECISE = {
12027
12013
  const COS = {
12028
12014
  description: _t("Cosine of an angle provided in radians."),
12029
12015
  args: [arg("angle (number)", _t("The angle to find the cosine of, in radians."))],
12030
- returns: ["NUMBER"],
12031
12016
  compute: function (angle) {
12032
12017
  return Math.cos(toNumber(angle, this.locale));
12033
12018
  },
@@ -12039,7 +12024,6 @@ const COS = {
12039
12024
  const COSH = {
12040
12025
  description: _t("Hyperbolic cosine of any real number."),
12041
12026
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosine of."))],
12042
- returns: ["NUMBER"],
12043
12027
  compute: function (value) {
12044
12028
  return Math.cosh(toNumber(value, this.locale));
12045
12029
  },
@@ -12051,7 +12035,6 @@ const COSH = {
12051
12035
  const COT = {
12052
12036
  description: _t("Cotangent of an angle provided in radians."),
12053
12037
  args: [arg("angle (number)", _t("The angle to find the cotangent of, in radians."))],
12054
- returns: ["NUMBER"],
12055
12038
  compute: function (angle) {
12056
12039
  const _angle = toNumber(angle, this.locale);
12057
12040
  assertNotZero(_angle);
@@ -12065,7 +12048,6 @@ const COT = {
12065
12048
  const COTH = {
12066
12049
  description: _t("Hyperbolic cotangent of any real number."),
12067
12050
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cotangent of."))],
12068
- returns: ["NUMBER"],
12069
12051
  compute: function (value) {
12070
12052
  const _value = toNumber(value, this.locale);
12071
12053
  assertNotZero(_value);
@@ -12082,7 +12064,6 @@ const COUNTBLANK = {
12082
12064
  arg("value1 (any, range)", _t("The first value or range in which to count the number of blanks.")),
12083
12065
  arg("value2 (any, range, repeating)", _t("Additional values or ranges in which to count the number of blanks.")),
12084
12066
  ],
12085
- returns: ["NUMBER"],
12086
12067
  compute: function (...args) {
12087
12068
  return reduceAny(args, (acc, a) => {
12088
12069
  if (a === undefined) {
@@ -12108,7 +12089,6 @@ const COUNTIF = {
12108
12089
  arg("range (range)", _t("The range that is tested against criterion.")),
12109
12090
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12110
12091
  ],
12111
- returns: ["NUMBER"],
12112
12092
  compute: function (...args) {
12113
12093
  let count = 0;
12114
12094
  visitMatchingRanges(args, (i, j) => {
@@ -12129,7 +12109,6 @@ const COUNTIFS = {
12129
12109
  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.")),
12130
12110
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12131
12111
  ],
12132
- returns: ["NUMBER"],
12133
12112
  compute: function (...args) {
12134
12113
  let count = 0;
12135
12114
  visitMatchingRanges(args, (i, j) => {
@@ -12148,7 +12127,6 @@ const COUNTUNIQUE = {
12148
12127
  arg("value1 (any, range)", _t("The first value or range to consider for uniqueness.")),
12149
12128
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider for uniqueness.")),
12150
12129
  ],
12151
- returns: ["NUMBER"],
12152
12130
  compute: function (...args) {
12153
12131
  return countUnique(args);
12154
12132
  },
@@ -12165,7 +12143,6 @@ const COUNTUNIQUEIFS = {
12165
12143
  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.")),
12166
12144
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
12167
12145
  ],
12168
- returns: ["NUMBER"],
12169
12146
  compute: function (range, ...args) {
12170
12147
  let uniqueValues = new Set();
12171
12148
  visitMatchingRanges(args, (i, j) => {
@@ -12183,7 +12160,6 @@ const COUNTUNIQUEIFS = {
12183
12160
  const CSC = {
12184
12161
  description: _t("Cosecant of an angle provided in radians."),
12185
12162
  args: [arg("angle (number)", _t("The angle to find the cosecant of, in radians."))],
12186
- returns: ["NUMBER"],
12187
12163
  compute: function (angle) {
12188
12164
  const _angle = toNumber(angle, this.locale);
12189
12165
  assertNotZero(_angle);
@@ -12197,7 +12173,6 @@ const CSC = {
12197
12173
  const CSCH = {
12198
12174
  description: _t("Hyperbolic cosecant of any real number."),
12199
12175
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic cosecant of."))],
12200
- returns: ["NUMBER"],
12201
12176
  compute: function (value) {
12202
12177
  const _value = toNumber(value, this.locale);
12203
12178
  assertNotZero(_value);
@@ -12214,7 +12189,6 @@ const DECIMAL = {
12214
12189
  arg("value (string)", _t("The number to convert.")),
12215
12190
  arg("base (number)", _t("The base to convert the value from.")),
12216
12191
  ],
12217
- returns: ["NUMBER"],
12218
12192
  compute: function (value, base) {
12219
12193
  let _base = toNumber(base, this.locale);
12220
12194
  _base = Math.floor(_base);
@@ -12241,7 +12215,6 @@ const DECIMAL = {
12241
12215
  const DEGREES = {
12242
12216
  description: _t("Converts an angle value in radians to degrees."),
12243
12217
  args: [arg("angle (number)", _t("The angle to convert from radians to degrees."))],
12244
- returns: ["NUMBER"],
12245
12218
  compute: function (angle) {
12246
12219
  return (toNumber(angle, this.locale) * 180) / Math.PI;
12247
12220
  },
@@ -12253,7 +12226,6 @@ const DEGREES = {
12253
12226
  const EXP = {
12254
12227
  description: _t("Euler's number, e (~2.718) raised to a power."),
12255
12228
  args: [arg("value (number)", _t("The exponent to raise e."))],
12256
- returns: ["NUMBER"],
12257
12229
  compute: function (value) {
12258
12230
  return Math.exp(toNumber(value, this.locale));
12259
12231
  },
@@ -12268,7 +12240,6 @@ const FLOOR = {
12268
12240
  arg("value (number)", _t("The value to round down to the nearest integer multiple of factor.")),
12269
12241
  arg(`factor (number, default=${DEFAULT_FACTOR})`, _t("The number to whose multiples value will be rounded.")),
12270
12242
  ],
12271
- returns: ["NUMBER"],
12272
12243
  compute: function (value, factor = { value: DEFAULT_FACTOR }) {
12273
12244
  const _value = toNumber(value, this.locale);
12274
12245
  const _factor = toNumber(factor, this.locale);
@@ -12303,7 +12274,6 @@ const FLOOR_MATH = {
12303
12274
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded. The sign of significance will be ignored.")),
12304
12275
  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.")),
12305
12276
  ],
12306
- returns: ["NUMBER"],
12307
12277
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }, mode = { value: DEFAULT_MODE }) {
12308
12278
  const _significance = toNumber(significance, this.locale);
12309
12279
  const _number = toNumber(number, this.locale);
@@ -12324,7 +12294,6 @@ const FLOOR_PRECISE = {
12324
12294
  arg("number (number)", _t("The value to round down to the nearest integer multiple of significance.")),
12325
12295
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12326
12296
  ],
12327
- returns: ["NUMBER"],
12328
12297
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12329
12298
  const _significance = toNumber(significance, this.locale);
12330
12299
  const _number = toNumber(number, this.locale);
@@ -12341,7 +12310,6 @@ const FLOOR_PRECISE = {
12341
12310
  const ISEVEN = {
12342
12311
  description: _t("Whether the provided value is even."),
12343
12312
  args: [arg("value (number)", _t("The value to be verified as even."))],
12344
- returns: ["BOOLEAN"],
12345
12313
  compute: function (value) {
12346
12314
  const _value = strictToNumber(value, this.locale);
12347
12315
  return Math.floor(Math.abs(_value)) & 1 ? false : true;
@@ -12357,7 +12325,6 @@ const ISO_CEILING = {
12357
12325
  arg("number (number)", _t("The value to round up to the nearest integer multiple of significance.")),
12358
12326
  arg(`significance (number, default=${DEFAULT_SIGNIFICANCE})`, _t("The number to whose multiples number will be rounded.")),
12359
12327
  ],
12360
- returns: ["NUMBER"],
12361
12328
  compute: function (number, significance = { value: DEFAULT_SIGNIFICANCE }) {
12362
12329
  const _number = toNumber(number, this.locale);
12363
12330
  const _significance = toNumber(significance, this.locale);
@@ -12374,7 +12341,6 @@ const ISO_CEILING = {
12374
12341
  const ISODD = {
12375
12342
  description: _t("Whether the provided value is even."),
12376
12343
  args: [arg("value (number)", _t("The value to be verified as even."))],
12377
- returns: ["BOOLEAN"],
12378
12344
  compute: function (value) {
12379
12345
  const _value = strictToNumber(value, this.locale);
12380
12346
  return Math.floor(Math.abs(_value)) & 1 ? true : false;
@@ -12387,7 +12353,6 @@ const ISODD = {
12387
12353
  const LN = {
12388
12354
  description: _t("The logarithm of a number, base e (euler's number)."),
12389
12355
  args: [arg("value (number)", _t("The value for which to calculate the logarithm, base e."))],
12390
- returns: ["NUMBER"],
12391
12356
  compute: function (value) {
12392
12357
  const _value = toNumber(value, this.locale);
12393
12358
  assert(() => _value > 0, _t("The value (%s) must be strictly positive.", _value.toString()));
@@ -12413,7 +12378,6 @@ const MOD = {
12413
12378
  arg("dividend (number)", _t("The number to be divided to find the remainder.")),
12414
12379
  arg("divisor (number)", _t("The number to divide by.")),
12415
12380
  ],
12416
- returns: ["NUMBER"],
12417
12381
  compute: function (dividend, divisor) {
12418
12382
  const _divisor = toNumber(divisor, this.locale);
12419
12383
  const _dividend = toNumber(dividend, this.locale);
@@ -12432,7 +12396,6 @@ const MUNIT = {
12432
12396
  args: [
12433
12397
  arg("dimension (number)", _t("An integer specifying the dimension size of the unit matrix. It must be positive.")),
12434
12398
  ],
12435
- returns: ["RANGE<NUMBER>"],
12436
12399
  compute: function (n) {
12437
12400
  const _n = toInteger(n, this.locale);
12438
12401
  assertPositive(_t("The argument dimension must be positive"), _n);
@@ -12446,7 +12409,6 @@ const MUNIT = {
12446
12409
  const ODD = {
12447
12410
  description: _t("Rounds a number up to the nearest odd integer."),
12448
12411
  args: [arg("value (number)", _t("The value to round to the next greatest odd number."))],
12449
- returns: ["NUMBER"],
12450
12412
  compute: function (value) {
12451
12413
  const _value = toNumber(value, this.locale);
12452
12414
  let temp = Math.ceil(Math.abs(_value));
@@ -12464,7 +12426,6 @@ const ODD = {
12464
12426
  const PI = {
12465
12427
  description: _t("The number pi."),
12466
12428
  args: [],
12467
- returns: ["NUMBER"],
12468
12429
  compute: function () {
12469
12430
  return Math.PI;
12470
12431
  },
@@ -12479,7 +12440,6 @@ const POWER = {
12479
12440
  arg("base (number)", _t("The number to raise to the exponent power.")),
12480
12441
  arg("exponent (number)", _t("The exponent to raise base to.")),
12481
12442
  ],
12482
- returns: ["NUMBER"],
12483
12443
  compute: function (base, exponent) {
12484
12444
  const _base = toNumber(base, this.locale);
12485
12445
  const _exponent = toNumber(exponent, this.locale);
@@ -12497,7 +12457,6 @@ const PRODUCT = {
12497
12457
  arg("factor1 (number, range<number>)", _t("The first number or range to calculate for the product.")),
12498
12458
  arg("factor2 (number, range<number>, repeating)", _t("More numbers or ranges to calculate for the product.")),
12499
12459
  ],
12500
- returns: ["NUMBER"],
12501
12460
  compute: function (...factors) {
12502
12461
  let count = 0;
12503
12462
  let acc = 1;
@@ -12534,7 +12493,6 @@ const PRODUCT = {
12534
12493
  const RAND = {
12535
12494
  description: _t("A random number between 0 inclusive and 1 exclusive."),
12536
12495
  args: [],
12537
- returns: ["NUMBER"],
12538
12496
  compute: function () {
12539
12497
  return Math.random();
12540
12498
  },
@@ -12552,7 +12510,6 @@ const RANDARRAY = {
12552
12510
  arg("max (number, default=1)", _t("The maximum number you would like returned.")),
12553
12511
  arg("whole_number (number, default=FALSE)", _t("Return a whole number or a decimal value.")),
12554
12512
  ],
12555
- returns: ["RANGE<NUMBER>"],
12556
12513
  compute: function (rows = { value: 1 }, columns = { value: 1 }, min = { value: 0 }, max = { value: 1 }, wholeNumber = { value: false }) {
12557
12514
  const _cols = toInteger(columns, this.locale);
12558
12515
  const _rows = toInteger(rows, this.locale);
@@ -12590,7 +12547,6 @@ const RANDBETWEEN = {
12590
12547
  arg("low (number)", _t("The low end of the random range.")),
12591
12548
  arg("high (number)", _t("The high end of the random range.")),
12592
12549
  ],
12593
- returns: ["NUMBER"],
12594
12550
  compute: function (low, high) {
12595
12551
  let _low = toNumber(low, this.locale);
12596
12552
  if (!Number.isInteger(_low)) {
@@ -12617,7 +12573,6 @@ const ROUND = {
12617
12573
  arg("value (number)", _t("The value to round to places number of places.")),
12618
12574
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12619
12575
  ],
12620
- returns: ["NUMBER"],
12621
12576
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12622
12577
  const _value = toNumber(value, this.locale);
12623
12578
  let _places = toNumber(places, this.locale);
@@ -12648,7 +12603,6 @@ const ROUNDDOWN = {
12648
12603
  arg("value (number)", _t("The value to round to places number of places, always rounding down.")),
12649
12604
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12650
12605
  ],
12651
- returns: ["NUMBER"],
12652
12606
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12653
12607
  const _value = toNumber(value, this.locale);
12654
12608
  let _places = toNumber(places, this.locale);
@@ -12679,7 +12633,6 @@ const ROUNDUP = {
12679
12633
  arg("value (number)", _t("The value to round to places number of places, always rounding up.")),
12680
12634
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of decimal places to which to round.")),
12681
12635
  ],
12682
- returns: ["NUMBER"],
12683
12636
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12684
12637
  const _value = toNumber(value, this.locale);
12685
12638
  let _places = toNumber(places, this.locale);
@@ -12707,7 +12660,6 @@ const ROUNDUP = {
12707
12660
  const SEC = {
12708
12661
  description: _t("Secant of an angle provided in radians."),
12709
12662
  args: [arg("angle (number)", _t("The angle to find the secant of, in radians."))],
12710
- returns: ["NUMBER"],
12711
12663
  compute: function (angle) {
12712
12664
  return 1 / Math.cos(toNumber(angle, this.locale));
12713
12665
  },
@@ -12719,7 +12671,6 @@ const SEC = {
12719
12671
  const SECH = {
12720
12672
  description: _t("Hyperbolic secant of any real number."),
12721
12673
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic secant of."))],
12722
- returns: ["NUMBER"],
12723
12674
  compute: function (value) {
12724
12675
  return 1 / Math.cosh(toNumber(value, this.locale));
12725
12676
  },
@@ -12731,7 +12682,6 @@ const SECH = {
12731
12682
  const SIN = {
12732
12683
  description: _t("Sine of an angle provided in radians."),
12733
12684
  args: [arg("angle (number)", _t("The angle to find the sine of, in radians."))],
12734
- returns: ["NUMBER"],
12735
12685
  compute: function (angle) {
12736
12686
  return Math.sin(toNumber(angle, this.locale));
12737
12687
  },
@@ -12743,7 +12693,6 @@ const SIN = {
12743
12693
  const SINH = {
12744
12694
  description: _t("Hyperbolic sine of any real number."),
12745
12695
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic sine of."))],
12746
- returns: ["NUMBER"],
12747
12696
  compute: function (value) {
12748
12697
  return Math.sinh(toNumber(value, this.locale));
12749
12698
  },
@@ -12755,7 +12704,6 @@ const SINH = {
12755
12704
  const SQRT = {
12756
12705
  description: _t("Positive square root of a positive number."),
12757
12706
  args: [arg("value (number)", _t("The number for which to calculate the positive square root."))],
12758
- returns: ["NUMBER"],
12759
12707
  compute: function (value) {
12760
12708
  const _value = toNumber(value, this.locale);
12761
12709
  assert(() => _value >= 0, _t("The value (%s) must be positive or null.", _value.toString()));
@@ -12772,7 +12720,6 @@ const SUM = {
12772
12720
  arg("value1 (number, range<number>)", _t("The first number or range to add together.")),
12773
12721
  arg("value2 (number, range<number>, repeating)", _t("Additional numbers or ranges to add to value1.")),
12774
12722
  ],
12775
- returns: ["NUMBER"],
12776
12723
  compute: function (...values) {
12777
12724
  const v1 = values[0];
12778
12725
  return {
@@ -12792,7 +12739,6 @@ const SUMIF = {
12792
12739
  arg("criterion (string)", _t("The pattern or test to apply to range.")),
12793
12740
  arg("sum_range (range, default=criteria_range)", _t("The range to be summed, if different from range.")),
12794
12741
  ],
12795
- returns: ["NUMBER"],
12796
12742
  compute: function (criteriaRange, criterion, sumRange) {
12797
12743
  if (sumRange === undefined) {
12798
12744
  sumRange = criteriaRange;
@@ -12820,7 +12766,6 @@ const SUMIFS = {
12820
12766
  arg("criteria_range2 (any, range, repeating)", _t("Additional ranges to check.")),
12821
12767
  arg("criterion2 (string, repeating)", _t("Additional criteria to check.")),
12822
12768
  ],
12823
- returns: ["NUMBER"],
12824
12769
  compute: function (sumRange, ...criters) {
12825
12770
  let sum = 0;
12826
12771
  visitMatchingRanges(criters, (i, j) => {
@@ -12839,7 +12784,6 @@ const SUMIFS = {
12839
12784
  const TAN = {
12840
12785
  description: _t("Tangent of an angle provided in radians."),
12841
12786
  args: [arg("angle (number)", _t("The angle to find the tangent of, in radians."))],
12842
- returns: ["NUMBER"],
12843
12787
  compute: function (angle) {
12844
12788
  return Math.tan(toNumber(angle, this.locale));
12845
12789
  },
@@ -12851,7 +12795,6 @@ const TAN = {
12851
12795
  const TANH = {
12852
12796
  description: _t("Hyperbolic tangent of any real number."),
12853
12797
  args: [arg("value (number)", _t("Any real value to calculate the hyperbolic tangent of."))],
12854
- returns: ["NUMBER"],
12855
12798
  compute: function (value) {
12856
12799
  return Math.tanh(toNumber(value, this.locale));
12857
12800
  },
@@ -12875,7 +12818,6 @@ const TRUNC = {
12875
12818
  arg("value (number)", _t("The value to be truncated.")),
12876
12819
  arg(`places (number, default=${DEFAULT_PLACES})`, _t("The number of significant digits to the right of the decimal point to retain.")),
12877
12820
  ],
12878
- returns: ["NUMBER"],
12879
12821
  compute: function (value, places = { value: DEFAULT_PLACES }) {
12880
12822
  const _value = toNumber(value, this.locale);
12881
12823
  const _places = toNumber(places, this.locale);
@@ -12889,7 +12831,6 @@ const TRUNC = {
12889
12831
  const INT = {
12890
12832
  description: _t("Rounds a number down to the nearest integer that is less than or equal to it."),
12891
12833
  args: [arg("value (number)", _t("The number to round down to the nearest integer."))],
12892
- returns: ["NUMBER"],
12893
12834
  compute: function (value) {
12894
12835
  return Math.floor(toNumber(value, this.locale));
12895
12836
  },
@@ -13248,7 +13189,6 @@ const AVEDEV = {
13248
13189
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
13249
13190
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
13250
13191
  ],
13251
- returns: ["NUMBER"],
13252
13192
  compute: function (...values) {
13253
13193
  let count = 0;
13254
13194
  const sum = reduceNumbers(values, (acc, a) => {
@@ -13270,7 +13210,6 @@ const AVERAGE = {
13270
13210
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13271
13211
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13272
13212
  ],
13273
- returns: ["NUMBER"],
13274
13213
  compute: function (...values) {
13275
13214
  return {
13276
13215
  value: average(values, this.locale),
@@ -13292,7 +13231,6 @@ const AVERAGE_WEIGHTED = {
13292
13231
  arg("additional_values (number, range<number>, repeating)", _t("Additional values to average.")),
13293
13232
  arg("additional_weights (number, range<number>, repeating)", _t("Additional weights.")),
13294
13233
  ],
13295
- returns: ["NUMBER"],
13296
13234
  compute: function (...args) {
13297
13235
  let sum = 0;
13298
13236
  let count = 0;
@@ -13340,7 +13278,6 @@ const AVERAGEA = {
13340
13278
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the average value.")),
13341
13279
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the average value.")),
13342
13280
  ],
13343
- returns: ["NUMBER"],
13344
13281
  compute: function (...args) {
13345
13282
  let count = 0;
13346
13283
  const sum = reduceNumbersTextAs0(args, (acc, a) => {
@@ -13365,7 +13302,6 @@ const AVERAGEIF = {
13365
13302
  arg("criterion (string)", _t("The pattern or test to apply to criteria_range.")),
13366
13303
  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.")),
13367
13304
  ],
13368
- returns: ["NUMBER"],
13369
13305
  compute: function (criteriaRange, criterion, averageRange) {
13370
13306
  const _averageRange = averageRange === undefined ? toMatrix(criteriaRange) : toMatrix(averageRange);
13371
13307
  let count = 0;
@@ -13394,7 +13330,6 @@ const AVERAGEIFS = {
13394
13330
  arg("criteria_range2 (any, range, repeating)", _t("Additional criteria_range and criterion to check.")),
13395
13331
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13396
13332
  ],
13397
- returns: ["NUMBER"],
13398
13333
  compute: function (averageRange, ...args) {
13399
13334
  const _averageRange = toMatrix(averageRange);
13400
13335
  let count = 0;
@@ -13420,7 +13355,6 @@ const COUNT = {
13420
13355
  arg("value1 (number, range<number>)", _t("The first value or range to consider when counting.")),
13421
13356
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when counting.")),
13422
13357
  ],
13423
- returns: ["NUMBER"],
13424
13358
  compute: function (...values) {
13425
13359
  return countNumbers(values, this.locale);
13426
13360
  },
@@ -13435,7 +13369,6 @@ const COUNTA = {
13435
13369
  arg("value1 (any, range)", _t("The first value or range to consider when counting.")),
13436
13370
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when counting.")),
13437
13371
  ],
13438
- returns: ["NUMBER"],
13439
13372
  compute: function (...values) {
13440
13373
  return countAny(values);
13441
13374
  },
@@ -13452,7 +13385,6 @@ const COVAR = {
13452
13385
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13453
13386
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13454
13387
  ],
13455
- returns: ["NUMBER"],
13456
13388
  compute: function (dataY, dataX) {
13457
13389
  return covariance(dataY, dataX, false);
13458
13390
  },
@@ -13467,7 +13399,6 @@ const COVARIANCE_P = {
13467
13399
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13468
13400
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13469
13401
  ],
13470
- returns: ["NUMBER"],
13471
13402
  compute: function (dataY, dataX) {
13472
13403
  return covariance(dataY, dataX, false);
13473
13404
  },
@@ -13482,7 +13413,6 @@ const COVARIANCE_S = {
13482
13413
  arg("data_y (any, range)", _t("The range representing the array or matrix of dependent data.")),
13483
13414
  arg("data_x (any, range)", _t("The range representing the array or matrix of independent data.")),
13484
13415
  ],
13485
- returns: ["NUMBER"],
13486
13416
  compute: function (dataY, dataX) {
13487
13417
  return covariance(dataY, dataX, true);
13488
13418
  },
@@ -13498,7 +13428,6 @@ const FORECAST = {
13498
13428
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13499
13429
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13500
13430
  ],
13501
- returns: ["NUMBER"],
13502
13431
  compute: function (x, dataY, dataX) {
13503
13432
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13504
13433
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
@@ -13516,7 +13445,6 @@ const GROWTH = {
13516
13445
  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.")),
13517
13446
  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.")),
13518
13447
  ],
13519
- returns: ["NUMBER"],
13520
13448
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
13521
13449
  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)));
13522
13450
  },
@@ -13530,7 +13458,6 @@ const INTERCEPT = {
13530
13458
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13531
13459
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13532
13460
  ],
13533
- returns: ["NUMBER"],
13534
13461
  compute: function (dataY, dataX) {
13535
13462
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13536
13463
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -13547,7 +13474,6 @@ const LARGE = {
13547
13474
  arg("data (any, range)", _t("Array or range containing the dataset to consider.")),
13548
13475
  arg("n (number)", _t("The rank from largest to smallest of the element to return.")),
13549
13476
  ],
13550
- returns: ["NUMBER"],
13551
13477
  compute: function (data, n) {
13552
13478
  const _n = Math.trunc(toNumber(n?.value, this.locale));
13553
13479
  let largests = [];
@@ -13582,7 +13508,6 @@ const LINEST = {
13582
13508
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13583
13509
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13584
13510
  ],
13585
- returns: ["NUMBER"],
13586
13511
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13587
13512
  return fullLinearRegression(toNumberMatrix(dataX, "the first argument (data_y)"), toNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13588
13513
  },
@@ -13599,7 +13524,6 @@ const LOGEST = {
13599
13524
  arg("calculate_b (boolean, default=TRUE)", _t("A flag specifying wheter to compute the slope or not")),
13600
13525
  arg("verbose (boolean, default=FALSE)", _t("A flag specifying whether to return additional regression statistics or only the linear coefficients and the y-intercept")),
13601
13526
  ],
13602
- returns: ["NUMBER"],
13603
13527
  compute: function (dataY, dataX = [[]], calculateB = { value: true }, verbose = { value: false }) {
13604
13528
  const coeffs = fullLinearRegression(toNumberMatrix(dataX, "the second argument (data_x)"), logM(toNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13605
13529
  for (let i = 0; i < coeffs.length; i++) {
@@ -13618,7 +13542,6 @@ const MATTHEWS = {
13618
13542
  arg("data_x (range)", _t("The range representing the array or matrix of observed data.")),
13619
13543
  arg("data_y (range)", _t("The range representing the array or matrix of predicted data.")),
13620
13544
  ],
13621
- returns: ["NUMBER"],
13622
13545
  compute: function (dataX, dataY) {
13623
13546
  const flatX = dataX.flat();
13624
13547
  const flatY = dataY.flat();
@@ -13662,7 +13585,6 @@ const MAX = {
13662
13585
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the maximum value.")),
13663
13586
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13664
13587
  ],
13665
- returns: ["NUMBER"],
13666
13588
  compute: function (...values) {
13667
13589
  return {
13668
13590
  value: max(values, this.locale),
@@ -13680,7 +13602,6 @@ const MAXA = {
13680
13602
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the maximum value.")),
13681
13603
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the maximum value.")),
13682
13604
  ],
13683
- returns: ["NUMBER"],
13684
13605
  compute: function (...args) {
13685
13606
  const maxa = reduceNumbersTextAs0(args, (acc, a) => {
13686
13607
  return Math.max(a, acc);
@@ -13701,7 +13622,6 @@ const MAXIFS = {
13701
13622
  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.")),
13702
13623
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13703
13624
  ],
13704
- returns: ["NUMBER"],
13705
13625
  compute: function (range, ...args) {
13706
13626
  let result = -Infinity;
13707
13627
  visitMatchingRanges(args, (i, j) => {
@@ -13723,7 +13643,6 @@ const MEDIAN = {
13723
13643
  arg("value1 (any, range)", _t("The first value or range to consider when calculating the median value.")),
13724
13644
  arg("value2 (any, range, repeating)", _t("Additional values or ranges to consider when calculating the median value.")),
13725
13645
  ],
13726
- returns: ["NUMBER"],
13727
13646
  compute: function (...values) {
13728
13647
  let data = [];
13729
13648
  visitNumbers(values, (value) => {
@@ -13745,7 +13664,6 @@ const MIN = {
13745
13664
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13746
13665
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13747
13666
  ],
13748
- returns: ["NUMBER"],
13749
13667
  compute: function (...values) {
13750
13668
  return {
13751
13669
  value: min(values, this.locale),
@@ -13763,7 +13681,6 @@ const MINA = {
13763
13681
  arg("value1 (number, range<number>)", _t("The first value or range to consider when calculating the minimum value.")),
13764
13682
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to consider when calculating the minimum value.")),
13765
13683
  ],
13766
- returns: ["NUMBER"],
13767
13684
  compute: function (...args) {
13768
13685
  const mina = reduceNumbersTextAs0(args, (acc, a) => {
13769
13686
  return Math.min(a, acc);
@@ -13784,7 +13701,6 @@ const MINIFS = {
13784
13701
  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.")),
13785
13702
  arg("criterion2 (string, repeating)", _t("The pattern or test to apply to criteria_range2.")),
13786
13703
  ],
13787
- returns: ["NUMBER"],
13788
13704
  compute: function (range, ...args) {
13789
13705
  let result = Infinity;
13790
13706
  visitMatchingRanges(args, (i, j) => {
@@ -13827,7 +13743,6 @@ const PEARSON = {
13827
13743
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
13828
13744
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
13829
13745
  ],
13830
- returns: ["NUMBER"],
13831
13746
  compute: function (dataY, dataX) {
13832
13747
  return pearson(dataY, dataX);
13833
13748
  },
@@ -13844,7 +13759,6 @@ const PERCENTILE = {
13844
13759
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13845
13760
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13846
13761
  ],
13847
- returns: ["NUMBER"],
13848
13762
  compute: function (data, percentile) {
13849
13763
  return PERCENTILE_INC.compute.bind(this)(data, percentile);
13850
13764
  },
@@ -13859,7 +13773,6 @@ const PERCENTILE_EXC = {
13859
13773
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13860
13774
  arg("percentile (number)", _t("The percentile, exclusive of 0 and 1, whose value within 'data' will be calculated and returned.")),
13861
13775
  ],
13862
- returns: ["NUMBER"],
13863
13776
  compute: function (data, percentile) {
13864
13777
  return {
13865
13778
  value: centile([data], percentile, false, this.locale),
@@ -13877,7 +13790,6 @@ const PERCENTILE_INC = {
13877
13790
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13878
13791
  arg("percentile (number)", _t("The percentile whose value within data will be calculated and returned.")),
13879
13792
  ],
13880
- returns: ["NUMBER"],
13881
13793
  compute: function (data, percentile) {
13882
13794
  return {
13883
13795
  value: centile([data], percentile, true, this.locale),
@@ -13897,7 +13809,6 @@ const POLYFIT_COEFFS = {
13897
13809
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13898
13810
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13899
13811
  ],
13900
- returns: ["RANGE<NUMBER>"],
13901
13812
  compute: function (dataY, dataX, order, intercept = { value: true }) {
13902
13813
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13903
13814
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
@@ -13916,7 +13827,6 @@ const POLYFIT_FORECAST = {
13916
13827
  arg("order (number)", _t("The order of the polynomial to fit the data, between 1 and 6.")),
13917
13828
  arg("intercept (boolean, default=TRUE)", _t("A flag specifying whether to compute the intercept or not.")),
13918
13829
  ],
13919
- returns: ["NUMBER"],
13920
13830
  compute: function (x, dataY, dataX, order, intercept = { value: true }) {
13921
13831
  const _order = toNumber(order, this.locale);
13922
13832
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
@@ -13934,7 +13844,6 @@ const QUARTILE = {
13934
13844
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13935
13845
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13936
13846
  ],
13937
- returns: ["NUMBER"],
13938
13847
  compute: function (data, quartileNumber) {
13939
13848
  return QUARTILE_INC.compute.bind(this)(data, quartileNumber);
13940
13849
  },
@@ -13949,7 +13858,6 @@ const QUARTILE_EXC = {
13949
13858
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13950
13859
  arg("quartile_number (number)", _t("Which quartile value, exclusive of 0 and 4, to return.")),
13951
13860
  ],
13952
- returns: ["NUMBER"],
13953
13861
  compute: function (data, quartileNumber) {
13954
13862
  const _quartileNumber = Math.trunc(toNumber(quartileNumber, this.locale));
13955
13863
  const percent = { value: 0.25 * _quartileNumber };
@@ -13969,7 +13877,6 @@ const QUARTILE_INC = {
13969
13877
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
13970
13878
  arg("quartile_number (number)", _t("Which quartile value to return.")),
13971
13879
  ],
13972
- returns: ["NUMBER"],
13973
13880
  compute: function (data, quartileNumber) {
13974
13881
  const percent = { value: 0.25 * Math.trunc(toNumber(quartileNumber, this.locale)) };
13975
13882
  return {
@@ -13988,7 +13895,6 @@ const RANK = {
13988
13895
  arg("data (range)", _t("The range containing the dataset to consider.")),
13989
13896
  arg("is_ascending (boolean, default=FALSE)", _t("Whether to consider the values in data in descending or ascending order.")),
13990
13897
  ],
13991
- returns: ["ANY"],
13992
13898
  compute: function (value, data, isAscending = { value: false }) {
13993
13899
  const _isAscending = toBoolean(isAscending);
13994
13900
  const _value = toNumber(value, this.locale);
@@ -14024,7 +13930,6 @@ const RSQ = {
14024
13930
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14025
13931
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14026
13932
  ],
14027
- returns: ["NUMBER"],
14028
13933
  compute: function (dataY, dataX) {
14029
13934
  return Math.pow(pearson(dataX, dataY), 2.0);
14030
13935
  },
@@ -14039,7 +13944,6 @@ const SLOPE = {
14039
13944
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14040
13945
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14041
13946
  ],
14042
- returns: ["NUMBER"],
14043
13947
  compute: function (dataY, dataX) {
14044
13948
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14045
13949
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
@@ -14056,7 +13960,6 @@ const SMALL = {
14056
13960
  arg("data (any, range)", _t("The array or range containing the dataset to consider.")),
14057
13961
  arg("n (number)", _t("The rank from smallest to largest of the element to return.")),
14058
13962
  ],
14059
- returns: ["NUMBER"],
14060
13963
  compute: function (data, n) {
14061
13964
  const _n = Math.trunc(toNumber(n?.value, this.locale));
14062
13965
  let largests = [];
@@ -14089,7 +13992,6 @@ const SPEARMAN = {
14089
13992
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14090
13993
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14091
13994
  ],
14092
- returns: ["NUMBER"],
14093
13995
  compute: function (dataX, dataY) {
14094
13996
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14095
13997
  const n = flatDataX.length;
@@ -14116,7 +14018,6 @@ const STDEV = {
14116
14018
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14117
14019
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14118
14020
  ],
14119
- returns: ["NUMBER"],
14120
14021
  compute: function (...args) {
14121
14022
  return Math.sqrt(VAR.compute.bind(this)(...args));
14122
14023
  },
@@ -14131,7 +14032,6 @@ const STDEV_P = {
14131
14032
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14132
14033
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14133
14034
  ],
14134
- returns: ["NUMBER"],
14135
14035
  compute: function (...args) {
14136
14036
  return Math.sqrt(VAR_P.compute.bind(this)(...args));
14137
14037
  },
@@ -14146,7 +14046,6 @@ const STDEV_S = {
14146
14046
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14147
14047
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14148
14048
  ],
14149
- returns: ["NUMBER"],
14150
14049
  compute: function (...args) {
14151
14050
  return Math.sqrt(VAR_S.compute.bind(this)(...args));
14152
14051
  },
@@ -14161,7 +14060,6 @@ const STDEVA = {
14161
14060
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14162
14061
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14163
14062
  ],
14164
- returns: ["NUMBER"],
14165
14063
  compute: function (...args) {
14166
14064
  return Math.sqrt(VARA.compute.bind(this)(...args));
14167
14065
  },
@@ -14176,7 +14074,6 @@ const STDEVP = {
14176
14074
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14177
14075
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14178
14076
  ],
14179
- returns: ["NUMBER"],
14180
14077
  compute: function (...args) {
14181
14078
  return Math.sqrt(VARP.compute.bind(this)(...args));
14182
14079
  },
@@ -14191,7 +14088,6 @@ const STDEVPA = {
14191
14088
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14192
14089
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14193
14090
  ],
14194
- returns: ["NUMBER"],
14195
14091
  compute: function (...args) {
14196
14092
  return Math.sqrt(VARPA.compute.bind(this)(...args));
14197
14093
  },
@@ -14206,7 +14102,6 @@ const STEYX = {
14206
14102
  arg("data_y (range<number>)", _t("The range representing the array or matrix of dependent data.")),
14207
14103
  arg("data_x (range<number>)", _t("The range representing the array or matrix of independent data.")),
14208
14104
  ],
14209
- returns: ["NUMBER"],
14210
14105
  compute: function (dataY, dataX) {
14211
14106
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14212
14107
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
@@ -14225,7 +14120,6 @@ const TREND = {
14225
14120
  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.")),
14226
14121
  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.")),
14227
14122
  ],
14228
- returns: ["NUMBER"],
14229
14123
  compute: function (knownDataY, knownDataX = [[]], newDataX = [[]], b = { value: true }) {
14230
14124
  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));
14231
14125
  },
@@ -14239,7 +14133,6 @@ const VAR = {
14239
14133
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14240
14134
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14241
14135
  ],
14242
- returns: ["NUMBER"],
14243
14136
  compute: function (...args) {
14244
14137
  return variance(args, true, false, this.locale);
14245
14138
  },
@@ -14254,7 +14147,6 @@ const VAR_P = {
14254
14147
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14255
14148
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14256
14149
  ],
14257
- returns: ["NUMBER"],
14258
14150
  compute: function (...args) {
14259
14151
  return variance(args, false, false, this.locale);
14260
14152
  },
@@ -14269,7 +14161,6 @@ const VAR_S = {
14269
14161
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14270
14162
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14271
14163
  ],
14272
- returns: ["NUMBER"],
14273
14164
  compute: function (...args) {
14274
14165
  return variance(args, true, false, this.locale);
14275
14166
  },
@@ -14284,7 +14175,6 @@ const VARA = {
14284
14175
  arg("value1 (number, range<number>)", _t("The first value or range of the sample.")),
14285
14176
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the sample.")),
14286
14177
  ],
14287
- returns: ["NUMBER"],
14288
14178
  compute: function (...args) {
14289
14179
  return variance(args, true, true, this.locale);
14290
14180
  },
@@ -14299,7 +14189,6 @@ const VARP = {
14299
14189
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14300
14190
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14301
14191
  ],
14302
- returns: ["NUMBER"],
14303
14192
  compute: function (...args) {
14304
14193
  return variance(args, false, false, this.locale);
14305
14194
  },
@@ -14314,7 +14203,6 @@ const VARPA = {
14314
14203
  arg("value1 (number, range<number>)", _t("The first value or range of the population.")),
14315
14204
  arg("value2 (number, range<number>, repeating)", _t("Additional values or ranges to include in the population.")),
14316
14205
  ],
14317
- returns: ["NUMBER"],
14318
14206
  compute: function (...args) {
14319
14207
  return variance(args, false, true, this.locale);
14320
14208
  },
@@ -14480,7 +14368,6 @@ const databaseArgs = [
14480
14368
  const DAVERAGE = {
14481
14369
  description: _t("Average of a set of values from a table-like range."),
14482
14370
  args: databaseArgs,
14483
- returns: ["NUMBER"],
14484
14371
  compute: function (database, field, criteria) {
14485
14372
  const cells = getMatchingCells(database, field, criteria, this.locale);
14486
14373
  return AVERAGE.compute.bind(this)([cells]);
@@ -14493,7 +14380,6 @@ const DAVERAGE = {
14493
14380
  const DCOUNT = {
14494
14381
  description: _t("Counts values from a table-like range."),
14495
14382
  args: databaseArgs,
14496
- returns: ["NUMBER"],
14497
14383
  compute: function (database, field, criteria) {
14498
14384
  const cells = getMatchingCells(database, field, criteria, this.locale);
14499
14385
  return COUNT.compute.bind(this)([cells]);
@@ -14506,7 +14392,6 @@ const DCOUNT = {
14506
14392
  const DCOUNTA = {
14507
14393
  description: _t("Counts values and text from a table-like range."),
14508
14394
  args: databaseArgs,
14509
- returns: ["NUMBER"],
14510
14395
  compute: function (database, field, criteria) {
14511
14396
  const cells = getMatchingCells(database, field, criteria, this.locale);
14512
14397
  return COUNTA.compute.bind(this)([cells]);
@@ -14519,7 +14404,6 @@ const DCOUNTA = {
14519
14404
  const DGET = {
14520
14405
  description: _t("Single value from a table-like range."),
14521
14406
  args: databaseArgs,
14522
- returns: ["NUMBER"],
14523
14407
  compute: function (database, field, criteria) {
14524
14408
  const cells = getMatchingCells(database, field, criteria, this.locale);
14525
14409
  assert(() => cells.length === 1, _t("More than one match found in DGET evaluation."));
@@ -14533,7 +14417,6 @@ const DGET = {
14533
14417
  const DMAX = {
14534
14418
  description: _t("Maximum of values from a table-like range."),
14535
14419
  args: databaseArgs,
14536
- returns: ["NUMBER"],
14537
14420
  compute: function (database, field, criteria) {
14538
14421
  const cells = getMatchingCells(database, field, criteria, this.locale);
14539
14422
  return MAX.compute.bind(this)([cells]);
@@ -14546,7 +14429,6 @@ const DMAX = {
14546
14429
  const DMIN = {
14547
14430
  description: _t("Minimum of values from a table-like range."),
14548
14431
  args: databaseArgs,
14549
- returns: ["NUMBER"],
14550
14432
  compute: function (database, field, criteria) {
14551
14433
  const cells = getMatchingCells(database, field, criteria, this.locale);
14552
14434
  return MIN.compute.bind(this)([cells]);
@@ -14559,7 +14441,6 @@ const DMIN = {
14559
14441
  const DPRODUCT = {
14560
14442
  description: _t("Product of values from a table-like range."),
14561
14443
  args: databaseArgs,
14562
- returns: ["NUMBER"],
14563
14444
  compute: function (database, field, criteria) {
14564
14445
  const cells = getMatchingCells(database, field, criteria, this.locale);
14565
14446
  return PRODUCT.compute.bind(this)([cells]);
@@ -14572,7 +14453,6 @@ const DPRODUCT = {
14572
14453
  const DSTDEV = {
14573
14454
  description: _t("Standard deviation of population sample from table."),
14574
14455
  args: databaseArgs,
14575
- returns: ["NUMBER"],
14576
14456
  compute: function (database, field, criteria) {
14577
14457
  const cells = getMatchingCells(database, field, criteria, this.locale);
14578
14458
  return STDEV.compute.bind(this)([cells]);
@@ -14585,7 +14465,6 @@ const DSTDEV = {
14585
14465
  const DSTDEVP = {
14586
14466
  description: _t("Standard deviation of entire population from table."),
14587
14467
  args: databaseArgs,
14588
- returns: ["NUMBER"],
14589
14468
  compute: function (database, field, criteria) {
14590
14469
  const cells = getMatchingCells(database, field, criteria, this.locale);
14591
14470
  return STDEVP.compute.bind(this)([cells]);
@@ -14598,7 +14477,6 @@ const DSTDEVP = {
14598
14477
  const DSUM = {
14599
14478
  description: _t("Sum of values from a table-like range."),
14600
14479
  args: databaseArgs,
14601
- returns: ["NUMBER"],
14602
14480
  compute: function (database, field, criteria) {
14603
14481
  const cells = getMatchingCells(database, field, criteria, this.locale);
14604
14482
  return SUM.compute.bind(this)([cells]);
@@ -14611,7 +14489,6 @@ const DSUM = {
14611
14489
  const DVAR = {
14612
14490
  description: _t("Variance of population sample from table-like range."),
14613
14491
  args: databaseArgs,
14614
- returns: ["NUMBER"],
14615
14492
  compute: function (database, field, criteria) {
14616
14493
  const cells = getMatchingCells(database, field, criteria, this.locale);
14617
14494
  return VAR.compute.bind(this)([cells]);
@@ -14624,7 +14501,6 @@ const DVAR = {
14624
14501
  const DVARP = {
14625
14502
  description: _t("Variance of a population from a table-like range."),
14626
14503
  args: databaseArgs,
14627
- returns: ["NUMBER"],
14628
14504
  compute: function (database, field, criteria) {
14629
14505
  const cells = getMatchingCells(database, field, criteria, this.locale);
14630
14506
  return VARP.compute.bind(this)([cells]);
@@ -14669,7 +14545,6 @@ const DATE = {
14669
14545
  arg("month (number)", _t("The month component of the date.")),
14670
14546
  arg("day (number)", _t("The day component of the date.")),
14671
14547
  ],
14672
- returns: ["DATE"],
14673
14548
  compute: function (year, month, day) {
14674
14549
  let _year = Math.trunc(toNumber(year, this.locale));
14675
14550
  const _month = Math.trunc(toNumber(month, this.locale));
@@ -14700,7 +14575,6 @@ const DATEDIF = {
14700
14575
  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.")),
14701
14576
  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).')),
14702
14577
  ],
14703
- returns: ["NUMBER"],
14704
14578
  compute: function (startDate, endDate, unit) {
14705
14579
  const _unit = toString(unit).toUpperCase();
14706
14580
  assert(() => Object.values(TIME_UNIT).includes(_unit), expectStringSetError(Object.values(TIME_UNIT), toString(unit)));
@@ -14753,7 +14627,6 @@ const DATEDIF = {
14753
14627
  const DATEVALUE = {
14754
14628
  description: _t("Converts a date string to a date value."),
14755
14629
  args: [arg("date_string (string)", _t("The string representing the date."))],
14756
- returns: ["NUMBER"],
14757
14630
  compute: function (dateString) {
14758
14631
  const _dateString = toString(dateString);
14759
14632
  const internalDate = parseDateTime(_dateString, this.locale);
@@ -14768,7 +14641,6 @@ const DATEVALUE = {
14768
14641
  const DAY = {
14769
14642
  description: _t("Day of the month that a specific date falls on."),
14770
14643
  args: [arg("date (string)", _t("The date from which to extract the day."))],
14771
- returns: ["NUMBER"],
14772
14644
  compute: function (date) {
14773
14645
  return toJsDate(date, this.locale).getDate();
14774
14646
  },
@@ -14783,7 +14655,6 @@ const DAYS = {
14783
14655
  arg("end_date (date)", _t("The end of the date range.")),
14784
14656
  arg("start_date (date)", _t("The start of the date range.")),
14785
14657
  ],
14786
- returns: ["NUMBER"],
14787
14658
  compute: function (endDate, startDate) {
14788
14659
  const _endDate = toJsDate(endDate, this.locale);
14789
14660
  const _startDate = toJsDate(startDate, this.locale);
@@ -14803,7 +14674,6 @@ const DAYS360 = {
14803
14674
  arg("end_date (date)", _t("The end date to consider in the calculation.")),
14804
14675
  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")),
14805
14676
  ],
14806
- returns: ["NUMBER"],
14807
14677
  compute: function (startDate, endDate, method = { value: DEFAULT_DAY_COUNT_METHOD }) {
14808
14678
  const _startDate = Math.trunc(toNumber(startDate, this.locale));
14809
14679
  const _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -14822,7 +14692,6 @@ const EDATE = {
14822
14692
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14823
14693
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to calculate.")),
14824
14694
  ],
14825
- returns: ["DATE"],
14826
14695
  compute: function (startDate, months) {
14827
14696
  const _startDate = toJsDate(startDate, this.locale);
14828
14697
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14843,7 +14712,6 @@ const EOMONTH = {
14843
14712
  arg("start_date (date)", _t("The date from which to calculate the result.")),
14844
14713
  arg("months (number)", _t("The number of months before (negative) or after (positive) 'start_date' to consider.")),
14845
14714
  ],
14846
- returns: ["DATE"],
14847
14715
  compute: function (startDate, months) {
14848
14716
  const _startDate = toJsDate(startDate, this.locale);
14849
14717
  const _months = Math.trunc(toNumber(months, this.locale));
@@ -14863,7 +14731,6 @@ const EOMONTH = {
14863
14731
  const HOUR = {
14864
14732
  description: _t("Hour component of a specific time."),
14865
14733
  args: [arg("time (date)", _t("The time from which to calculate the hour component."))],
14866
- returns: ["NUMBER"],
14867
14734
  compute: function (date) {
14868
14735
  return toJsDate(date, this.locale).getHours();
14869
14736
  },
@@ -14877,7 +14744,6 @@ const ISOWEEKNUM = {
14877
14744
  args: [
14878
14745
  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.")),
14879
14746
  ],
14880
- returns: ["NUMBER"],
14881
14747
  compute: function (date) {
14882
14748
  const _date = toJsDate(date, this.locale);
14883
14749
  const y = _date.getFullYear();
@@ -14949,7 +14815,6 @@ const ISOWEEKNUM = {
14949
14815
  const MINUTE = {
14950
14816
  description: _t("Minute component of a specific time."),
14951
14817
  args: [arg("time (date)", _t("The time from which to calculate the minute component."))],
14952
- returns: ["NUMBER"],
14953
14818
  compute: function (date) {
14954
14819
  return toJsDate(date, this.locale).getMinutes();
14955
14820
  },
@@ -14961,7 +14826,6 @@ const MINUTE = {
14961
14826
  const MONTH = {
14962
14827
  description: _t("Month of the year a specific date falls in"),
14963
14828
  args: [arg("date (date)", _t("The date from which to extract the month."))],
14964
- returns: ["NUMBER"],
14965
14829
  compute: function (date) {
14966
14830
  return toJsDate(date, this.locale).getMonth() + 1;
14967
14831
  },
@@ -14977,7 +14841,6 @@ const NETWORKDAYS = {
14977
14841
  arg("end_date (date)", _t("The end date of the period from which to calculate the number of net working days.")),
14978
14842
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the date serial numbers to consider holidays.")),
14979
14843
  ],
14980
- returns: ["NUMBER"],
14981
14844
  compute: function (startDate, endDate, holidays) {
14982
14845
  return NETWORKDAYS_INTL.compute.bind(this)(startDate, endDate, { value: 1 }, holidays);
14983
14846
  },
@@ -15058,7 +14921,6 @@ const NETWORKDAYS_INTL = {
15058
14921
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15059
14922
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider as holidays.")),
15060
14923
  ],
15061
- returns: ["NUMBER"],
15062
14924
  compute: function (startDate, endDate, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15063
14925
  const _startDate = toJsDate(startDate, this.locale);
15064
14926
  const _endDate = toJsDate(endDate, this.locale);
@@ -15093,7 +14955,6 @@ const NETWORKDAYS_INTL = {
15093
14955
  const NOW = {
15094
14956
  description: _t("Current date and time as a date value."),
15095
14957
  args: [],
15096
- returns: ["DATE"],
15097
14958
  compute: function () {
15098
14959
  const today = DateTime.now();
15099
14960
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
@@ -15111,7 +14972,6 @@ const NOW = {
15111
14972
  const SECOND = {
15112
14973
  description: _t("Minute component of a specific time."),
15113
14974
  args: [arg("time (date)", _t("The time from which to calculate the second component."))],
15114
- returns: ["NUMBER"],
15115
14975
  compute: function (date) {
15116
14976
  return toJsDate(date, this.locale).getSeconds();
15117
14977
  },
@@ -15127,7 +14987,6 @@ const TIME = {
15127
14987
  arg("minute (number)", _t("The minute component of the time.")),
15128
14988
  arg("second (number)", _t("The second component of the time.")),
15129
14989
  ],
15130
- returns: ["DATE"],
15131
14990
  compute: function (hour, minute, second) {
15132
14991
  let _hour = Math.trunc(toNumber(hour, this.locale));
15133
14992
  let _minute = Math.trunc(toNumber(minute, this.locale));
@@ -15151,7 +15010,6 @@ const TIME = {
15151
15010
  const TIMEVALUE = {
15152
15011
  description: _t("Converts a time string into its serial number representation."),
15153
15012
  args: [arg("time_string (string)", _t("The string that holds the time representation."))],
15154
- returns: ["NUMBER"],
15155
15013
  compute: function (timeString) {
15156
15014
  const _timeString = toString(timeString);
15157
15015
  const internalDate = parseDateTime(_timeString, this.locale);
@@ -15167,7 +15025,6 @@ const TIMEVALUE = {
15167
15025
  const TODAY = {
15168
15026
  description: _t("Current date as a date value."),
15169
15027
  args: [],
15170
- returns: ["DATE"],
15171
15028
  compute: function () {
15172
15029
  const today = DateTime.now();
15173
15030
  const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
@@ -15187,7 +15044,6 @@ const WEEKDAY = {
15187
15044
  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.")),
15188
15045
  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.")),
15189
15046
  ],
15190
- returns: ["NUMBER"],
15191
15047
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15192
15048
  const _date = toJsDate(date, this.locale);
15193
15049
  const _type = Math.round(toNumber(type, this.locale));
@@ -15210,7 +15066,6 @@ const WEEKNUM = {
15210
15066
  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.")),
15211
15067
  arg(`type (number, default=${DEFAULT_TYPE})`, _t("A number representing the day that a week starts on. Sunday = 1.")),
15212
15068
  ],
15213
- returns: ["NUMBER"],
15214
15069
  compute: function (date, type = { value: DEFAULT_TYPE }) {
15215
15070
  const _date = toJsDate(date, this.locale);
15216
15071
  const _type = Math.round(toNumber(type, this.locale));
@@ -15251,7 +15106,6 @@ const WORKDAY = {
15251
15106
  arg("num_days (number)", _t("The number of working days to advance from start_date. If negative, counts backwards.")),
15252
15107
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15253
15108
  ],
15254
- returns: ["NUMBER"],
15255
15109
  compute: function (startDate, numDays, holidays = { value: null }) {
15256
15110
  return WORKDAY_INTL.compute.bind(this)(startDate, numDays, { value: 1 }, holidays);
15257
15111
  },
@@ -15268,7 +15122,6 @@ const WORKDAY_INTL = {
15268
15122
  arg(`weekend (any, default=${DEFAULT_WEEKEND})`, _t("A number or string representing which days of the week are considered weekends.")),
15269
15123
  arg("holidays (date, range<date>, optional)", _t("A range or array constant containing the dates to consider holidays.")),
15270
15124
  ],
15271
- returns: ["DATE"],
15272
15125
  compute: function (startDate, numDays, weekend = { value: DEFAULT_WEEKEND }, holidays) {
15273
15126
  let _startDate = toJsDate(startDate, this.locale);
15274
15127
  let _numDays = Math.trunc(toNumber(numDays, this.locale));
@@ -15308,7 +15161,6 @@ const WORKDAY_INTL = {
15308
15161
  const YEAR = {
15309
15162
  description: _t("Year specified by a given date."),
15310
15163
  args: [arg("date (date)", _t("The date from which to extract the year."))],
15311
- returns: ["NUMBER"],
15312
15164
  compute: function (date) {
15313
15165
  return toJsDate(date, this.locale).getFullYear();
15314
15166
  },
@@ -15325,7 +15177,6 @@ const YEARFRAC = {
15325
15177
  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.")),
15326
15178
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION$1})`, _t("An indicator of what day count method to use.")),
15327
15179
  ],
15328
- returns: ["NUMBER"],
15329
15180
  compute: function (startDate, endDate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION$1 }) {
15330
15181
  let _startDate = Math.trunc(toNumber(startDate, this.locale));
15331
15182
  let _endDate = Math.trunc(toNumber(endDate, this.locale));
@@ -15342,7 +15193,6 @@ const YEARFRAC = {
15342
15193
  const MONTH_START = {
15343
15194
  description: _t("First day of the month preceding a date."),
15344
15195
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15345
- returns: ["DATE"],
15346
15196
  compute: function (date) {
15347
15197
  const _startDate = toJsDate(date, this.locale);
15348
15198
  const yStart = _startDate.getFullYear();
@@ -15360,7 +15210,6 @@ const MONTH_START = {
15360
15210
  const MONTH_END = {
15361
15211
  description: _t("Last day of the month following a date."),
15362
15212
  args: [arg("date (date)", _t("The date from which to calculate the result."))],
15363
- returns: ["DATE"],
15364
15213
  compute: function (date) {
15365
15214
  return EOMONTH.compute.bind(this)(date, { value: 0 });
15366
15215
  },
@@ -15371,7 +15220,6 @@ const MONTH_END = {
15371
15220
  const QUARTER = {
15372
15221
  description: _t("Quarter of the year a specific date falls in"),
15373
15222
  args: [arg("date (date)", _t("The date from which to extract the quarter."))],
15374
- returns: ["NUMBER"],
15375
15223
  compute: function (date) {
15376
15224
  return Math.ceil((toJsDate(date, this.locale).getMonth() + 1) / 3);
15377
15225
  },
@@ -15382,7 +15230,6 @@ const QUARTER = {
15382
15230
  const QUARTER_START = {
15383
15231
  description: _t("First day of the quarter of the year a specific date falls in."),
15384
15232
  args: [arg("date (date)", _t("The date from which to calculate the start of quarter."))],
15385
- returns: ["DATE"],
15386
15233
  compute: function (date) {
15387
15234
  const quarter = QUARTER.compute.bind(this)(date);
15388
15235
  const year = YEAR.compute.bind(this)(date);
@@ -15399,7 +15246,6 @@ const QUARTER_START = {
15399
15246
  const QUARTER_END = {
15400
15247
  description: _t("Last day of the quarter of the year a specific date falls in."),
15401
15248
  args: [arg("date (date)", _t("The date from which to calculate the end of quarter."))],
15402
- returns: ["DATE"],
15403
15249
  compute: function (date) {
15404
15250
  const quarter = QUARTER.compute.bind(this)(date);
15405
15251
  const year = YEAR.compute.bind(this)(date);
@@ -15416,7 +15262,6 @@ const QUARTER_END = {
15416
15262
  const YEAR_START = {
15417
15263
  description: _t("First day of the year a specific date falls in."),
15418
15264
  args: [arg("date (date)", _t("The date from which to calculate the start of the year."))],
15419
- returns: ["DATE"],
15420
15265
  compute: function (date) {
15421
15266
  const year = YEAR.compute.bind(this)(date);
15422
15267
  const jsDate = new DateTime(year, 0, 1);
@@ -15432,7 +15277,6 @@ const YEAR_START = {
15432
15277
  const YEAR_END = {
15433
15278
  description: _t("Last day of the year a specific date falls in."),
15434
15279
  args: [arg("date (date)", _t("The date from which to calculate the end of the year."))],
15435
- returns: ["DATE"],
15436
15280
  compute: function (date) {
15437
15281
  const year = YEAR.compute.bind(this)(date);
15438
15282
  const jsDate = new DateTime(year + 1, 0, 0);
@@ -15489,7 +15333,6 @@ const DELTA = {
15489
15333
  arg("number1 (number)", _t("The first number to compare.")),
15490
15334
  arg(`number2 (number, default=${DEFAULT_DELTA_ARG})`, _t("The second number to compare.")),
15491
15335
  ],
15492
- returns: ["NUMBER"],
15493
15336
  compute: function (number1, number2 = { value: DEFAULT_DELTA_ARG }) {
15494
15337
  const _number1 = toNumber(number1, this.locale);
15495
15338
  const _number2 = toNumber(number2, this.locale);
@@ -15680,7 +15523,6 @@ const FILTER = {
15680
15523
  arg("condition1 (boolean, range<boolean>)", _t("A column or row containing true or false values corresponding to the first column or row of range.")),
15681
15524
  arg("condition2 (boolean, range<boolean>, repeating)", _t("Additional column or row containing true or false values.")),
15682
15525
  ],
15683
- returns: ["RANGE<ANY>"],
15684
15526
  compute: function (range, ...conditions) {
15685
15527
  let _array = toMatrix(range);
15686
15528
  const _conditionsMatrices = conditions.map((cond) => matrixMap(toMatrix(cond), (data) => data.value));
@@ -15714,7 +15556,6 @@ const SORT = {
15714
15556
  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.")),
15715
15557
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15716
15558
  ],
15717
- returns: ["RANGE"],
15718
15559
  compute: function (range, ...sortingCriteria) {
15719
15560
  const _range = transposeMatrix(range);
15720
15561
  return transposeMatrix(sortMatrix(_range, this.locale, ...sortingCriteria));
@@ -15733,7 +15574,6 @@ const SORTN = {
15733
15574
  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.")),
15734
15575
  arg("is_ascending (boolean, repeating)", _t("TRUE or FALSE indicating whether to sort sort_column in ascending order. FALSE sorts in descending order.")),
15735
15576
  ],
15736
- returns: ["RANGE"],
15737
15577
  compute: function (range, n, displayTiesMode, ...sortingCriteria) {
15738
15578
  const _n = toNumber(n?.value ?? 1, this.locale);
15739
15579
  assert(() => _n >= 0, _t("Wrong value of 'n'. Expected a positive number. Got %s.", _n));
@@ -15801,7 +15641,6 @@ const UNIQUE = {
15801
15641
  arg("by_column (boolean, default=FALSE)", _t("Whether to filter the data by columns or by rows.")),
15802
15642
  arg("exactly_once (boolean, default=FALSE)", _t("Whether to return only entries with no duplicates.")),
15803
15643
  ],
15804
- returns: ["RANGE<NUMBER>"],
15805
15644
  compute: function (range = { value: "" }, byColumn, exactlyOnce) {
15806
15645
  if (!isMatrix(range)) {
15807
15646
  return [[range]];
@@ -16026,7 +15865,6 @@ const ACCRINTM = {
16026
15865
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16027
15866
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16028
15867
  ],
16029
- returns: ["NUMBER"],
16030
15868
  compute: function (issue, maturity, rate, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16031
15869
  const start = Math.trunc(toNumber(issue, this.locale));
16032
15870
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16057,7 +15895,6 @@ const AMORLINC = {
16057
15895
  arg("rate (number)", _t("The deprecation rate.")),
16058
15896
  arg("day_count_convention (number, optional)", _t("An indicator of what day count method to use.")),
16059
15897
  ],
16060
- returns: ["NUMBER"],
16061
15898
  compute: function (cost, purchaseDate, firstPeriodEnd, salvage, period, rate, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16062
15899
  dayCountConvention = dayCountConvention || 0;
16063
15900
  const _cost = toNumber(cost, this.locale);
@@ -16106,7 +15943,6 @@ const AMORLINC = {
16106
15943
  const COUPDAYS = {
16107
15944
  description: _t("Days in coupon period containing settlement date."),
16108
15945
  args: COUPON_FUNCTION_ARGS,
16109
- returns: ["NUMBER"],
16110
15946
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16111
15947
  dayCountConvention = dayCountConvention || 0;
16112
15948
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16133,7 +15969,6 @@ const COUPDAYS = {
16133
15969
  const COUPDAYBS = {
16134
15970
  description: _t("Days from settlement until next coupon."),
16135
15971
  args: COUPON_FUNCTION_ARGS,
16136
- returns: ["NUMBER"],
16137
15972
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16138
15973
  dayCountConvention = dayCountConvention || 0;
16139
15974
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16190,7 +16025,6 @@ const COUPDAYBS = {
16190
16025
  const COUPDAYSNC = {
16191
16026
  description: _t("Days from settlement until next coupon."),
16192
16027
  args: COUPON_FUNCTION_ARGS,
16193
- returns: ["NUMBER"],
16194
16028
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16195
16029
  dayCountConvention = dayCountConvention || 0;
16196
16030
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16220,7 +16054,6 @@ const COUPDAYSNC = {
16220
16054
  const COUPNCD = {
16221
16055
  description: _t("Next coupon date after the settlement date."),
16222
16056
  args: COUPON_FUNCTION_ARGS,
16223
- returns: ["NUMBER"],
16224
16057
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16225
16058
  dayCountConvention = dayCountConvention || 0;
16226
16059
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16246,7 +16079,6 @@ const COUPNCD = {
16246
16079
  const COUPNUM = {
16247
16080
  description: _t("Number of coupons between settlement and maturity."),
16248
16081
  args: COUPON_FUNCTION_ARGS,
16249
- returns: ["NUMBER"],
16250
16082
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16251
16083
  dayCountConvention = dayCountConvention || 0;
16252
16084
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16273,7 +16105,6 @@ const COUPNUM = {
16273
16105
  const COUPPCD = {
16274
16106
  description: _t("Last coupon date prior to or on the settlement date."),
16275
16107
  args: COUPON_FUNCTION_ARGS,
16276
- returns: ["NUMBER"],
16277
16108
  compute: function (settlement, maturity, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16278
16109
  dayCountConvention = dayCountConvention || 0;
16279
16110
  const start = Math.trunc(toNumber(settlement, this.locale));
@@ -16306,7 +16137,6 @@ const CUMIPMT = {
16306
16137
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16307
16138
  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.")),
16308
16139
  ],
16309
- returns: ["NUMBER"],
16310
16140
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16311
16141
  const first = toNumber(firstPeriod, this.locale);
16312
16142
  const last = toNumber(lastPeriod, this.locale);
@@ -16338,7 +16168,6 @@ const CUMPRINC = {
16338
16168
  arg("last_period (number)", _t("The number of the payment period to end the cumulative calculation.")),
16339
16169
  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.")),
16340
16170
  ],
16341
- returns: ["NUMBER"],
16342
16171
  compute: function (rate, numberOfPeriods, presentValue, firstPeriod, lastPeriod, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16343
16172
  const first = toNumber(firstPeriod, this.locale);
16344
16173
  const last = toNumber(lastPeriod, this.locale);
@@ -16369,7 +16198,6 @@ const DB = {
16369
16198
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16370
16199
  arg("month (number, optional)", _t("The number of months in the first year of depreciation.")),
16371
16200
  ],
16372
- returns: ["NUMBER"],
16373
16201
  // to do: replace by dollar format
16374
16202
  compute: function (cost, salvage, life, period, ...args) {
16375
16203
  const _cost = toNumber(cost, this.locale);
@@ -16438,7 +16266,6 @@ const DDB = {
16438
16266
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
16439
16267
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The factor by which depreciation decreases.")),
16440
16268
  ],
16441
- returns: ["NUMBER"],
16442
16269
  compute: function (cost, salvage, life, period, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }) {
16443
16270
  const _cost = toNumber(cost, this.locale);
16444
16271
  const _salvage = toNumber(salvage, this.locale);
@@ -16464,7 +16291,6 @@ const DISC = {
16464
16291
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
16465
16292
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16466
16293
  ],
16467
- returns: ["NUMBER"],
16468
16294
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16469
16295
  dayCountConvention = dayCountConvention || 0;
16470
16296
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -16500,7 +16326,6 @@ const DOLLARDE = {
16500
16326
  arg("fractional_price (number)", _t("The price quotation given using fractional decimal conventions.")),
16501
16327
  arg("unit (number)", _t("The units of the fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16502
16328
  ],
16503
- returns: ["NUMBER"],
16504
16329
  compute: function (fractionalPrice, unit) {
16505
16330
  const price = toNumber(fractionalPrice, this.locale);
16506
16331
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16521,7 +16346,6 @@ const DOLLARFR = {
16521
16346
  arg("decimal_price (number)", _t("The price quotation given as a decimal value.")),
16522
16347
  arg("unit (number)", _t("The units of the desired fraction, e.g. 8 for 1/8ths or 32 for 1/32nds.")),
16523
16348
  ],
16524
- returns: ["NUMBER"],
16525
16349
  compute: function (decimalPrice, unit) {
16526
16350
  const price = toNumber(decimalPrice, this.locale);
16527
16351
  const _unit = Math.trunc(toNumber(unit, this.locale));
@@ -16546,7 +16370,6 @@ const DURATION = {
16546
16370
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16547
16371
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16548
16372
  ],
16549
- returns: ["NUMBER"],
16550
16373
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16551
16374
  const start = Math.trunc(toNumber(settlement, this.locale));
16552
16375
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -16587,7 +16410,6 @@ const EFFECT = {
16587
16410
  arg("nominal_rate (number)", _t("The nominal interest rate per year.")),
16588
16411
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16589
16412
  ],
16590
- returns: ["NUMBER"],
16591
16413
  compute: function (nominal_rate, periods_per_year) {
16592
16414
  const nominal = toNumber(nominal_rate, this.locale);
16593
16415
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16617,7 +16439,6 @@ const FV = {
16617
16439
  arg(`present_value (number, default=${DEFAULT_PRESENT_VALUE})`, _t("The current value of the annuity.")),
16618
16440
  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.")),
16619
16441
  ],
16620
- returns: ["NUMBER"],
16621
16442
  // to do: replace by dollar format
16622
16443
  compute: function (rate, numberOfPeriods, paymentAmount, presentValue = { value: DEFAULT_PRESENT_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16623
16444
  presentValue = presentValue || 0;
@@ -16643,7 +16464,6 @@ const FVSCHEDULE = {
16643
16464
  arg("principal (number)", _t("The amount of initial capital or value to compound against.")),
16644
16465
  arg("rate_schedule (number, range<number>)", _t("A series of interest rates to compound against the principal.")),
16645
16466
  ],
16646
- returns: ["NUMBER"],
16647
16467
  compute: function (principalAmount, rateSchedule) {
16648
16468
  const principal = toNumber(principalAmount, this.locale);
16649
16469
  return reduceAny([rateSchedule], (acc, rate) => acc * (1 + toNumber(rate, this.locale)), principal);
@@ -16662,7 +16482,6 @@ const INTRATE = {
16662
16482
  arg("redemption (number)", _t("The amount to be received at maturity.")),
16663
16483
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16664
16484
  ],
16665
- returns: ["NUMBER"],
16666
16485
  compute: function (settlement, maturity, investment, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16667
16486
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
16668
16487
  const _maturity = Math.trunc(toNumber(maturity, this.locale));
@@ -16701,7 +16520,6 @@ const IPMT = {
16701
16520
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16702
16521
  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.")),
16703
16522
  ],
16704
- returns: ["NUMBER"],
16705
16523
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16706
16524
  const r = toNumber(rate, this.locale);
16707
16525
  const period = toNumber(currentPeriod, this.locale);
@@ -16726,7 +16544,6 @@ const IRR = {
16726
16544
  arg("cashflow_amounts (number, range<number>)", _t("An array or range containing the income or payments associated with the investment.")),
16727
16545
  arg(`rate_guess (number, default=${DEFAULT_RATE_GUESS})`, _t("An estimate for what the internal rate of return will be.")),
16728
16546
  ],
16729
- returns: ["NUMBER"],
16730
16547
  compute: function (cashFlowAmounts, rateGuess = { value: DEFAULT_RATE_GUESS }) {
16731
16548
  const _rateGuess = toNumber(rateGuess, this.locale);
16732
16549
  assertRateGuessStrictlyGreaterThanMinusOne(_rateGuess);
@@ -16788,7 +16605,6 @@ const ISPMT = {
16788
16605
  arg("number_of_periods (number)", _t("The number of payments to be made.")),
16789
16606
  arg("present_value (number)", _t("The current value of the annuity.")),
16790
16607
  ],
16791
- returns: ["NUMBER"],
16792
16608
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue) {
16793
16609
  const interestRate = toNumber(rate, this.locale);
16794
16610
  const period = toNumber(currentPeriod, this.locale);
@@ -16813,7 +16629,6 @@ const MDURATION = {
16813
16629
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
16814
16630
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
16815
16631
  ],
16816
- returns: ["NUMBER"],
16817
16632
  compute: function (settlement, maturity, rate, securityYield, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
16818
16633
  const duration = DURATION.compute.bind(this)(settlement, maturity, rate, securityYield, frequency, dayCountConvention);
16819
16634
  const y = toNumber(securityYield, this.locale);
@@ -16832,7 +16647,6 @@ const MIRR = {
16832
16647
  arg("financing_rate (number)", _t("The interest rate paid on funds invested.")),
16833
16648
  arg("reinvestment_return_rate (number)", _t("The return (as a percentage) earned on reinvestment of income received from the investment.")),
16834
16649
  ],
16835
- returns: ["NUMBER"],
16836
16650
  compute: function (cashflowAmount, financingRate, reinvestmentRate) {
16837
16651
  const fRate = toNumber(financingRate, this.locale);
16838
16652
  const rRate = toNumber(reinvestmentRate, this.locale);
@@ -16884,7 +16698,6 @@ const NOMINAL = {
16884
16698
  arg("effective_rate (number)", _t("The effective interest rate per year.")),
16885
16699
  arg("periods_per_year (number)", _t("The number of compounding periods per year.")),
16886
16700
  ],
16887
- returns: ["NUMBER"],
16888
16701
  compute: function (effective_rate, periods_per_year) {
16889
16702
  const effective = toNumber(effective_rate, this.locale);
16890
16703
  const periods = Math.trunc(toNumber(periods_per_year, this.locale));
@@ -16907,7 +16720,6 @@ const NPER = {
16907
16720
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
16908
16721
  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.")),
16909
16722
  ],
16910
- returns: ["NUMBER"],
16911
16723
  compute: function (rate, paymentAmount, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
16912
16724
  futureValue = futureValue || 0;
16913
16725
  endOrBeginning = endOrBeginning || 0;
@@ -16955,7 +16767,6 @@ const NPV = {
16955
16767
  arg("cashflow1 (number, range<number>)", _t("The first future cash flow.")),
16956
16768
  arg("cashflow2 (number, range<number>, repeating)", _t("Additional future cash flows.")),
16957
16769
  ],
16958
- returns: ["NUMBER"],
16959
16770
  // to do: replace by dollar format
16960
16771
  compute: function (discount, ...values) {
16961
16772
  const _discount = toNumber(discount, this.locale);
@@ -16977,7 +16788,6 @@ const PDURATION = {
16977
16788
  arg("present_value (number)", _t("The investment's current value.")),
16978
16789
  arg("future_value (number)", _t("The investment's desired future value.")),
16979
16790
  ],
16980
- returns: ["NUMBER"],
16981
16791
  compute: function (rate, presentValue, futureValue) {
16982
16792
  const _rate = toNumber(rate, this.locale);
16983
16793
  const _presentValue = toNumber(presentValue, this.locale);
@@ -17017,7 +16827,6 @@ const PMT = {
17017
16827
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17018
16828
  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.")),
17019
16829
  ],
17020
- returns: ["NUMBER"],
17021
16830
  compute: function (rate, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17022
16831
  const n = toNumber(numberOfPeriods, this.locale);
17023
16832
  const r = toNumber(rate, this.locale);
@@ -17053,7 +16862,6 @@ const PPMT = {
17053
16862
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17054
16863
  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.")),
17055
16864
  ],
17056
- returns: ["NUMBER"],
17057
16865
  compute: function (rate, currentPeriod, numberOfPeriods, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17058
16866
  const n = toNumber(numberOfPeriods, this.locale);
17059
16867
  const r = toNumber(rate, this.locale);
@@ -17080,7 +16888,6 @@ const PV = {
17080
16888
  arg(`future_value (number, default=${DEFAULT_FUTURE_VALUE})`, _t("The future value remaining after the final payment has been made.")),
17081
16889
  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.")),
17082
16890
  ],
17083
- returns: ["NUMBER"],
17084
16891
  // to do: replace by dollar format
17085
16892
  compute: function (rate, numberOfPeriods, paymentAmount, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }) {
17086
16893
  futureValue = futureValue || 0;
@@ -17114,7 +16921,6 @@ const PRICE = {
17114
16921
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17115
16922
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17116
16923
  ],
17117
- returns: ["NUMBER"],
17118
16924
  compute: function (settlement, maturity, rate, securityYield, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17119
16925
  dayCountConvention = dayCountConvention || 0;
17120
16926
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17162,7 +16968,6 @@ const PRICEDISC = {
17162
16968
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17163
16969
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17164
16970
  ],
17165
- returns: ["NUMBER"],
17166
16971
  compute: function (settlement, maturity, discount, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17167
16972
  dayCountConvention = dayCountConvention || 0;
17168
16973
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17200,7 +17005,6 @@ const PRICEMAT = {
17200
17005
  arg("yield (number)", _t("The expected annual yield of the security.")),
17201
17006
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17202
17007
  ],
17203
- returns: ["NUMBER"],
17204
17008
  compute: function (settlement, maturity, issue, rate, securityYield, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17205
17009
  dayCountConvention = dayCountConvention || 0;
17206
17010
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17264,7 +17068,6 @@ const RATE = {
17264
17068
  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.")),
17265
17069
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the interest rate will be.")),
17266
17070
  ],
17267
- returns: ["NUMBER"],
17268
17071
  compute: function (numberOfPeriods, paymentPerPeriod, presentValue, futureValue = { value: DEFAULT_FUTURE_VALUE }, endOrBeginning = { value: DEFAULT_END_OR_BEGINNING }, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17269
17072
  const n = toNumber(numberOfPeriods, this.locale);
17270
17073
  const payment = toNumber(paymentPerPeriod, this.locale);
@@ -17310,7 +17113,6 @@ const RECEIVED = {
17310
17113
  arg("discount (number)", _t("The discount rate of the security invested in.")),
17311
17114
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17312
17115
  ],
17313
- returns: ["NUMBER"],
17314
17116
  compute: function (settlement, maturity, investment, discount, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17315
17117
  dayCountConvention = dayCountConvention || 0;
17316
17118
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17348,7 +17150,6 @@ const RRI = {
17348
17150
  arg("present_value (number)", _t("The present value of the investment.")),
17349
17151
  arg("future_value (number)", _t("The future value of the investment.")),
17350
17152
  ],
17351
- returns: ["NUMBER"],
17352
17153
  compute: function (numberOfPeriods, presentValue, futureValue) {
17353
17154
  const n = toNumber(numberOfPeriods, this.locale);
17354
17155
  const pv = toNumber(presentValue, this.locale);
@@ -17373,7 +17174,6 @@ const SLN = {
17373
17174
  arg("salvage (number)", _t("The value of the asset at the end of depreciation.")),
17374
17175
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17375
17176
  ],
17376
- returns: ["NUMBER"],
17377
17177
  compute: function (cost, salvage, life) {
17378
17178
  const _cost = toNumber(cost, this.locale);
17379
17179
  const _salvage = toNumber(salvage, this.locale);
@@ -17398,7 +17198,6 @@ const SYD = {
17398
17198
  arg("life (number)", _t("The number of periods over which the asset is depreciated.")),
17399
17199
  arg("period (number)", _t("The single period within life for which to calculate depreciation.")),
17400
17200
  ],
17401
- returns: ["NUMBER"],
17402
17201
  compute: function (cost, salvage, life, period) {
17403
17202
  const _cost = toNumber(cost, this.locale);
17404
17203
  const _salvage = toNumber(salvage, this.locale);
@@ -17447,7 +17246,6 @@ const TBILLPRICE = {
17447
17246
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17448
17247
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17449
17248
  ],
17450
- returns: ["NUMBER"],
17451
17249
  compute: function (settlement, maturity, discount) {
17452
17250
  const start = Math.trunc(toNumber(settlement, this.locale));
17453
17251
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17470,7 +17268,6 @@ const TBILLEQ = {
17470
17268
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17471
17269
  arg("discount (number)", _t("The discount rate of the bill at time of purchase.")),
17472
17270
  ],
17473
- returns: ["NUMBER"],
17474
17271
  compute: function (settlement, maturity, discount) {
17475
17272
  const start = Math.trunc(toNumber(settlement, this.locale));
17476
17273
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17528,7 +17325,6 @@ const TBILLYIELD = {
17528
17325
  arg("maturity (date)", _t("The maturity or end date of the security, when it can be redeemed at face, or par value.")),
17529
17326
  arg("price (number)", _t("The price at which the security is bought per 100 face value.")),
17530
17327
  ],
17531
- returns: ["NUMBER"],
17532
17328
  compute: function (settlement, maturity, price) {
17533
17329
  const start = Math.trunc(toNumber(settlement, this.locale));
17534
17330
  const end = Math.trunc(toNumber(maturity, this.locale));
@@ -17568,7 +17364,6 @@ const VDB = {
17568
17364
  arg(`factor (number, default=${DEFAULT_DDB_DEPRECIATION_FACTOR})`, _t("The number of months in the first year of depreciation.")),
17569
17365
  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.")),
17570
17366
  ],
17571
- returns: ["NUMBER"],
17572
17367
  compute: function (cost, salvage, life, startPeriod, endPeriod, factor = { value: DEFAULT_DDB_DEPRECIATION_FACTOR }, noSwitch = { value: DEFAULT_VDB_NO_SWITCH }) {
17573
17368
  factor = factor || 0;
17574
17369
  const _cost = toNumber(cost, this.locale);
@@ -17633,7 +17428,6 @@ const XIRR = {
17633
17428
  arg("cashflow_dates (range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17634
17429
  arg(`rate_guess (number, default=${RATE_GUESS_DEFAULT})`, _t("An estimate for what the internal rate of return will be.")),
17635
17430
  ],
17636
- returns: ["NUMBER"],
17637
17431
  compute: function (cashflowAmounts, cashflowDates, rateGuess = { value: RATE_GUESS_DEFAULT }) {
17638
17432
  const guess = toNumber(rateGuess, this.locale);
17639
17433
  const _cashFlows = cashflowAmounts.flat().map((val) => toNumber(val, this.locale));
@@ -17704,7 +17498,6 @@ const XNPV = {
17704
17498
  arg("cashflow_amounts (number, range<number>)", _t("An range containing the income or payments associated with the investment.")),
17705
17499
  arg("cashflow_dates (number, range<number>)", _t("An range with dates corresponding to the cash flows in cashflow_amounts.")),
17706
17500
  ],
17707
- returns: ["NUMBER"],
17708
17501
  compute: function (discount, cashflowAmounts, cashflowDates) {
17709
17502
  const rate = toNumber(discount, this.locale);
17710
17503
  const _cashFlows = isMatrix(cashflowAmounts)
@@ -17771,7 +17564,6 @@ const YIELD = {
17771
17564
  arg("frequency (number)", _t("The number of interest or coupon payments per year (1, 2, or 4).")),
17772
17565
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17773
17566
  ],
17774
- returns: ["NUMBER"],
17775
17567
  compute: function (settlement, maturity, rate, price, redemption, frequency, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17776
17568
  dayCountConvention = dayCountConvention || 0;
17777
17569
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17846,7 +17638,6 @@ const YIELDDISC = {
17846
17638
  arg("redemption (number)", _t("The redemption amount per 100 face value, or par.")),
17847
17639
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17848
17640
  ],
17849
- returns: ["NUMBER"],
17850
17641
  compute: function (settlement, maturity, price, redemption, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17851
17642
  dayCountConvention = dayCountConvention || 0;
17852
17643
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17883,7 +17674,6 @@ const YIELDMAT = {
17883
17674
  arg("price (number)", _t("The price at which the security is bought.")),
17884
17675
  arg(`day_count_convention (number, default=${DEFAULT_DAY_COUNT_CONVENTION} )`, _t("An indicator of what day count method to use.")),
17885
17676
  ],
17886
- returns: ["NUMBER"],
17887
17677
  compute: function (settlement, maturity, issue, rate, price, dayCountConvention = { value: DEFAULT_DAY_COUNT_CONVENTION }) {
17888
17678
  dayCountConvention = dayCountConvention || 0;
17889
17679
  const _settlement = Math.trunc(toNumber(settlement, this.locale));
@@ -17970,7 +17760,6 @@ const CELL = {
17970
17760
  arg("info_type (string)", _t("The type of information requested. Can be one of %s", CELL_INFO_TYPES.join(", "))),
17971
17761
  arg("reference (meta)", _t("The reference to the cell.")),
17972
17762
  ],
17973
- returns: ["ANY"],
17974
17763
  compute: function (info, reference) {
17975
17764
  const _info = toString(info).toLowerCase();
17976
17765
  assert(() => CELL_INFO_TYPES.includes(_info), _t("The info_type should be one of %s.", CELL_INFO_TYPES.join(", ")));
@@ -18021,7 +17810,6 @@ const CELL = {
18021
17810
  const ISERR = {
18022
17811
  description: _t("Whether a value is an error other than #N/A."),
18023
17812
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18024
- returns: ["BOOLEAN"],
18025
17813
  compute: function (data) {
18026
17814
  const value = data?.value;
18027
17815
  return isEvaluationError(value) && value !== CellErrorType.NotAvailable;
@@ -18034,7 +17822,6 @@ const ISERR = {
18034
17822
  const ISERROR = {
18035
17823
  description: _t("Whether a value is an error."),
18036
17824
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18037
- returns: ["BOOLEAN"],
18038
17825
  compute: function (data) {
18039
17826
  const value = data?.value;
18040
17827
  return isEvaluationError(value);
@@ -18047,7 +17834,6 @@ const ISERROR = {
18047
17834
  const ISLOGICAL = {
18048
17835
  description: _t("Whether a value is `true` or `false`."),
18049
17836
  args: [arg("value (any)", _t("The value to be verified as a logical TRUE or FALSE."))],
18050
- returns: ["BOOLEAN"],
18051
17837
  compute: function (value) {
18052
17838
  return typeof value?.value === "boolean";
18053
17839
  },
@@ -18059,7 +17845,6 @@ const ISLOGICAL = {
18059
17845
  const ISNA = {
18060
17846
  description: _t("Whether a value is the error #N/A."),
18061
17847
  args: [arg("value (any)", _t("The value to be verified as an error type."))],
18062
- returns: ["BOOLEAN"],
18063
17848
  compute: function (data) {
18064
17849
  return data?.value === CellErrorType.NotAvailable;
18065
17850
  },
@@ -18071,7 +17856,6 @@ const ISNA = {
18071
17856
  const ISNONTEXT = {
18072
17857
  description: _t("Whether a value is non-textual."),
18073
17858
  args: [arg("value (any)", _t("The value to be checked."))],
18074
- returns: ["BOOLEAN"],
18075
17859
  compute: function (value) {
18076
17860
  return !ISTEXT.compute.bind(this)(value);
18077
17861
  },
@@ -18083,7 +17867,6 @@ const ISNONTEXT = {
18083
17867
  const ISNUMBER = {
18084
17868
  description: _t("Whether a value is a number."),
18085
17869
  args: [arg("value (any)", _t("The value to be verified as a number."))],
18086
- returns: ["BOOLEAN"],
18087
17870
  compute: function (value) {
18088
17871
  return typeof value?.value === "number";
18089
17872
  },
@@ -18095,7 +17878,6 @@ const ISNUMBER = {
18095
17878
  const ISTEXT = {
18096
17879
  description: _t("Whether a value is text."),
18097
17880
  args: [arg("value (any)", _t("The value to be verified as text."))],
18098
- returns: ["BOOLEAN"],
18099
17881
  compute: function (value) {
18100
17882
  return typeof value?.value === "string" && isEvaluationError(value?.value) === false;
18101
17883
  },
@@ -18107,7 +17889,6 @@ const ISTEXT = {
18107
17889
  const ISBLANK = {
18108
17890
  description: _t("Whether the referenced cell is empty"),
18109
17891
  args: [arg("value (any)", _t("Reference to the cell that will be checked for emptiness."))],
18110
- returns: ["BOOLEAN"],
18111
17892
  compute: function (value) {
18112
17893
  return value?.value === null;
18113
17894
  },
@@ -18119,7 +17900,6 @@ const ISBLANK = {
18119
17900
  const NA = {
18120
17901
  description: _t("Returns the error value #N/A."),
18121
17902
  args: [],
18122
- returns: ["BOOLEAN"],
18123
17903
  compute: function () {
18124
17904
  return { value: CellErrorType.NotAvailable };
18125
17905
  },
@@ -18176,7 +17956,6 @@ const AND = {
18176
17956
  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.")),
18177
17957
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that represent logical values.")),
18178
17958
  ],
18179
- returns: ["BOOLEAN"],
18180
17959
  compute: function (...logicalExpressions) {
18181
17960
  const { result, foundBoolean } = boolAnd(logicalExpressions);
18182
17961
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18190,7 +17969,6 @@ const AND = {
18190
17969
  const FALSE = {
18191
17970
  description: _t("Logical value `false`."),
18192
17971
  args: [],
18193
- returns: ["BOOLEAN"],
18194
17972
  compute: function () {
18195
17973
  return false;
18196
17974
  },
@@ -18206,7 +17984,6 @@ const IF = {
18206
17984
  arg("value_if_true (any)", _t("The value the function returns if logical_expression is TRUE.")),
18207
17985
  arg("value_if_false (any, default=FALSE)", _t("The value the function returns if logical_expression is FALSE.")),
18208
17986
  ],
18209
- returns: ["ANY"],
18210
17987
  compute: function (logicalExpression, valueIfTrue, valueIfFalse) {
18211
17988
  const result = toBoolean(logicalExpression?.value) ? valueIfTrue : valueIfFalse;
18212
17989
  if (result === undefined) {
@@ -18228,7 +18005,6 @@ const IFERROR = {
18228
18005
  arg("value (any)", _t("The value to return if value itself is not an error.")),
18229
18006
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an error.")),
18230
18007
  ],
18231
- returns: ["ANY"],
18232
18008
  compute: function (value, valueIfError = { value: "" }) {
18233
18009
  const result = isEvaluationError(value?.value) ? valueIfError : value;
18234
18010
  if (result === undefined) {
@@ -18250,7 +18026,6 @@ const IFNA = {
18250
18026
  arg("value (any)", _t("The value to return if value itself is not #N/A an error.")),
18251
18027
  arg(`value_if_error (any, default="empty")`, _t("The value the function returns if value is an #N/A error.")),
18252
18028
  ],
18253
- returns: ["ANY"],
18254
18029
  compute: function (value, valueIfError = { value: "" }) {
18255
18030
  const result = value?.value === CellErrorType.NotAvailable ? valueIfError : value;
18256
18031
  if (result === undefined) {
@@ -18274,7 +18049,6 @@ const IFS = {
18274
18049
  arg("condition2 (boolean, repeating)", _t("Additional conditions to be evaluated if the previous ones are FALSE.")),
18275
18050
  arg("value2 (any, repeating)", _t("Additional values to be returned if their corresponding conditions are TRUE.")),
18276
18051
  ],
18277
- returns: ["ANY"],
18278
18052
  compute: function (...values) {
18279
18053
  assert(() => values.length % 2 === 0, _t("Wrong number of arguments. Expected an even number of arguments."));
18280
18054
  for (let n = 0; n < values.length - 1; n += 2) {
@@ -18301,7 +18075,6 @@ const NOT = {
18301
18075
  args: [
18302
18076
  arg("logical_expression (boolean)", _t("An expression or reference to a cell holding an expression that represents some logical value.")),
18303
18077
  ],
18304
- returns: ["BOOLEAN"],
18305
18078
  compute: function (logicalExpression) {
18306
18079
  return !toBoolean(logicalExpression);
18307
18080
  },
@@ -18316,7 +18089,6 @@ const OR = {
18316
18089
  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.")),
18317
18090
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18318
18091
  ],
18319
- returns: ["BOOLEAN"],
18320
18092
  compute: function (...logicalExpressions) {
18321
18093
  const { result, foundBoolean } = boolOr(logicalExpressions);
18322
18094
  assert(() => foundBoolean, _t("[[FUNCTION_NAME]] has no valid input data."));
@@ -18330,7 +18102,6 @@ const OR = {
18330
18102
  const TRUE = {
18331
18103
  description: _t("Logical value `true`."),
18332
18104
  args: [],
18333
- returns: ["BOOLEAN"],
18334
18105
  compute: function () {
18335
18106
  return true;
18336
18107
  },
@@ -18345,7 +18116,6 @@ const XOR = {
18345
18116
  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.")),
18346
18117
  arg("logical_expression2 (boolean, range<boolean>, repeating)", _t("More expressions that evaluate to logical values.")),
18347
18118
  ],
18348
- returns: ["BOOLEAN"],
18349
18119
  compute: function (...logicalExpressions) {
18350
18120
  let foundBoolean = false;
18351
18121
  let acc = false;
@@ -18374,9 +18144,229 @@ var logical = /*#__PURE__*/Object.freeze({
18374
18144
  XOR: XOR
18375
18145
  });
18376
18146
 
18377
- //TODO This registry is only used to disable the support of exploded pivot for spreadsheet
18378
- const supportedPivotExplodedFormulaRegistry = new Registry();
18379
- supportedPivotExplodedFormulaRegistry.add("SPREADSHEET", false);
18147
+ const pivotTimeAdapterRegistry = new Registry();
18148
+ function pivotTimeAdapter(granularity) {
18149
+ return pivotTimeAdapterRegistry.get(granularity);
18150
+ }
18151
+ /**
18152
+ * The Time Adapter: Managing Time Periods for Pivot Functions
18153
+ *
18154
+ * Overview:
18155
+ * A time adapter is responsible for managing time periods associated with pivot functions.
18156
+ * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
18157
+ * The adapter's primary role is to normalize period values between spreadsheet functions,
18158
+ * and the pivot.
18159
+ * By normalizing the period value, it can be stored consistently in the pivot.
18160
+ *
18161
+ * Normalization Process:
18162
+ * When working with functions in the spreadsheet, the time adapter normalizes
18163
+ * the provided period to facilitate accurate lookup of values in the pivot.
18164
+ * For instance, if the spreadsheet function represents a day period as a number generated
18165
+ * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
18166
+ *
18167
+ */
18168
+ /**
18169
+ * Normalized value: "12/25/2023"
18170
+ *
18171
+ * Note: Those two format are equivalent:
18172
+ * - "MM/dd/yyyy" (luxon format)
18173
+ * - "mm/dd/yyyy" (spreadsheet format)
18174
+ **/
18175
+ const dayAdapter = {
18176
+ normalizeFunctionValue(value) {
18177
+ const date = toNumber(value, DEFAULT_LOCALE);
18178
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
18179
+ },
18180
+ getFormat(locale) {
18181
+ return (locale ?? DEFAULT_LOCALE).dateFormat;
18182
+ },
18183
+ formatValue(normalizedValue, locale) {
18184
+ locale = locale ?? DEFAULT_LOCALE;
18185
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18186
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18187
+ },
18188
+ toCellValue(normalizedValue) {
18189
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18190
+ },
18191
+ };
18192
+ /**
18193
+ * normalizes day of month number
18194
+ */
18195
+ const dayOfMonthAdapter = {
18196
+ normalizeFunctionValue(value) {
18197
+ const day = toNumber(value, DEFAULT_LOCALE);
18198
+ if (day < 1 || day > 31) {
18199
+ throw new EvaluationError(_t("%s is not a valid day of month (it should be a number between 1 and 31)", day));
18200
+ }
18201
+ return day;
18202
+ },
18203
+ getFormat() {
18204
+ return "0";
18205
+ },
18206
+ formatValue(normalizedValue, locale) {
18207
+ locale = locale ?? DEFAULT_LOCALE;
18208
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18209
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18210
+ },
18211
+ toCellValue(normalizedValue) {
18212
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18213
+ },
18214
+ };
18215
+ /**
18216
+ * Normalized value: "2/2023" for week 2 of 2023
18217
+ */
18218
+ const weekAdapter = {
18219
+ normalizeFunctionValue(value) {
18220
+ const [week, year] = value.split("/");
18221
+ return `${Number(week)}/${Number(year)}`;
18222
+ },
18223
+ getFormat() {
18224
+ return undefined;
18225
+ },
18226
+ formatValue(normalizedValue) {
18227
+ const [week, year] = normalizedValue.split("/");
18228
+ return _t("W%(week)s %(year)s", { week, year });
18229
+ },
18230
+ toCellValue(normalizedValue) {
18231
+ return this.formatValue(normalizedValue);
18232
+ },
18233
+ };
18234
+ /**
18235
+ * normalizes iso week number
18236
+ */
18237
+ const isoWeekNumberAdapter = {
18238
+ normalizeFunctionValue(value) {
18239
+ const isoWeek = toNumber(value, DEFAULT_LOCALE);
18240
+ if (isoWeek < 0 || isoWeek > 53) {
18241
+ throw new EvaluationError(_t("%s is not a valid week (it should be a number between 0 and 53)", isoWeek));
18242
+ }
18243
+ return isoWeek;
18244
+ },
18245
+ getFormat() {
18246
+ return "0";
18247
+ },
18248
+ formatValue(normalizedValue, locale) {
18249
+ locale = locale ?? DEFAULT_LOCALE;
18250
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18251
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18252
+ },
18253
+ toCellValue(normalizedValue) {
18254
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18255
+ },
18256
+ };
18257
+ /**
18258
+ * normalized month value is a string formatted as "MM/yyyy" (luxon format)
18259
+ * e.g. "01/2020" for January 2020
18260
+ */
18261
+ const monthAdapter = {
18262
+ normalizeFunctionValue(value) {
18263
+ const date = toNumber(value, DEFAULT_LOCALE);
18264
+ return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
18265
+ },
18266
+ getFormat() {
18267
+ return "mmmm yyyy";
18268
+ },
18269
+ formatValue(normalizedValue, locale) {
18270
+ locale = locale ?? DEFAULT_LOCALE;
18271
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18272
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18273
+ },
18274
+ toCellValue(normalizedValue) {
18275
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18276
+ },
18277
+ };
18278
+ /**
18279
+ * normalizes month number
18280
+ */
18281
+ const monthNumberAdapter = {
18282
+ normalizeFunctionValue(value) {
18283
+ const month = toNumber(value, DEFAULT_LOCALE);
18284
+ if (month < 1 || month > 12) {
18285
+ throw new EvaluationError(_t("%s is not a valid month (it should be a number between 1 and 12)", month));
18286
+ }
18287
+ return month;
18288
+ },
18289
+ getFormat() {
18290
+ return "0";
18291
+ },
18292
+ formatValue(normalizedValue, locale) {
18293
+ locale = locale ?? DEFAULT_LOCALE;
18294
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18295
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18296
+ },
18297
+ toCellValue(normalizedValue) {
18298
+ return MONTHS[toNumber(normalizedValue, DEFAULT_LOCALE) - 1].toString();
18299
+ },
18300
+ };
18301
+ /**
18302
+ * normalized quarter value is "quarter/year"
18303
+ * e.g. "1/2020" for Q1 2020
18304
+ */
18305
+ const quarterAdapter = {
18306
+ normalizeFunctionValue(value) {
18307
+ const [quarter, year] = value.split("/");
18308
+ return `${quarter}/${year}`;
18309
+ },
18310
+ getFormat() {
18311
+ return undefined;
18312
+ },
18313
+ formatValue(normalizedValue) {
18314
+ const [quarter, year] = normalizedValue.split("/");
18315
+ return _t("Q%(quarter)s %(year)s", { quarter, year });
18316
+ },
18317
+ toCellValue(normalizedValue) {
18318
+ return this.formatValue(normalizedValue);
18319
+ },
18320
+ };
18321
+ /**
18322
+ * normalizes quarter number
18323
+ */
18324
+ const quarterNumberAdapter = {
18325
+ normalizeFunctionValue(value) {
18326
+ const quarter = toNumber(value, DEFAULT_LOCALE);
18327
+ if (quarter < 1 || quarter > 4) {
18328
+ throw new EvaluationError(_t("%s is not a valid quarter (it should be a number between 1 and 4)", quarter));
18329
+ }
18330
+ return quarter;
18331
+ },
18332
+ getFormat() {
18333
+ return "0";
18334
+ },
18335
+ formatValue(normalizedValue, locale) {
18336
+ locale = locale ?? DEFAULT_LOCALE;
18337
+ const value = toNumber(normalizedValue, DEFAULT_LOCALE);
18338
+ return formatValue(value, { locale, format: this.getFormat(locale) });
18339
+ },
18340
+ toCellValue(normalizedValue) {
18341
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18342
+ },
18343
+ };
18344
+ const yearAdapter = {
18345
+ normalizeFunctionValue(value) {
18346
+ return toNumber(value, DEFAULT_LOCALE);
18347
+ },
18348
+ getFormat() {
18349
+ return "0";
18350
+ },
18351
+ formatValue(normalizedValue, locale) {
18352
+ locale = locale ?? DEFAULT_LOCALE;
18353
+ return formatValue(normalizedValue, { locale, format: "0" });
18354
+ },
18355
+ toCellValue(normalizedValue) {
18356
+ return toNumber(normalizedValue, DEFAULT_LOCALE);
18357
+ },
18358
+ };
18359
+ pivotTimeAdapterRegistry
18360
+ .add("day", dayAdapter)
18361
+ .add("week", weekAdapter)
18362
+ .add("month", monthAdapter)
18363
+ .add("quarter", quarterAdapter)
18364
+ .add("year", yearAdapter)
18365
+ .add("day_of_month", dayOfMonthAdapter)
18366
+ .add("iso_week_number", isoWeekNumberAdapter)
18367
+ .add("month_number", monthNumberAdapter)
18368
+ .add("quarter_number", quarterNumberAdapter)
18369
+ .add("year_number", yearAdapter);
18380
18370
 
18381
18371
  const AGGREGATOR_NAMES = {
18382
18372
  count: _t("Count"),
@@ -18392,7 +18382,7 @@ const NUMBER_CHAR_AGGREGATORS = ["max", "min", "avg", "sum", "count_distinct", "
18392
18382
  const AGGREGATORS_BY_FIELD_TYPE = {
18393
18383
  integer: NUMBER_CHAR_AGGREGATORS,
18394
18384
  char: NUMBER_CHAR_AGGREGATORS,
18395
- //TODO Support for date and boolean
18385
+ boolean: ["count_distinct", "count", "bool_and", "bool_or"],
18396
18386
  };
18397
18387
  const AGGREGATORS = {};
18398
18388
  for (const type in AGGREGATORS_BY_FIELD_TYPE) {
@@ -18502,6 +18492,44 @@ function toPivotDomain(domainStr) {
18502
18492
  function flatPivotDomain(domain) {
18503
18493
  return domain.flatMap((arg) => [arg.field, arg.value]);
18504
18494
  }
18495
+ /**
18496
+ * Parses the value defining a pivot group in a PIVOT formula
18497
+ * e.g. given the following formula PIVOT.VALUE("1", "stage_id", "42", "status", "won"),
18498
+ * the two group values are "42" and "won".
18499
+ */
18500
+ function toNormalizedPivotValue(dimension, groupValue) {
18501
+ if (groupValue === null || groupValue === "null") {
18502
+ return null;
18503
+ }
18504
+ const groupValueString = typeof groupValue === "boolean"
18505
+ ? toString(groupValue).toLocaleLowerCase()
18506
+ : toString(groupValue);
18507
+ if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
18508
+ throw new EvaluationError(_t("Field %(field)s is not supported because of its type (%(type)s)", {
18509
+ field: dimension.displayName,
18510
+ type: dimension.type,
18511
+ }));
18512
+ }
18513
+ // represents a field which is not set (=False server side)
18514
+ if (groupValueString === "false") {
18515
+ return false;
18516
+ }
18517
+ const normalizer = pivotNormalizationValueRegistry.get(dimension.type);
18518
+ return normalizer(groupValueString, dimension.granularity);
18519
+ }
18520
+ function normalizeDateTime(value, granularity) {
18521
+ if (!granularity) {
18522
+ throw "";
18523
+ }
18524
+ return pivotTimeAdapter(granularity).normalizeFunctionValue(value);
18525
+ }
18526
+ const pivotNormalizationValueRegistry = new Registry();
18527
+ pivotNormalizationValueRegistry
18528
+ .add("date", normalizeDateTime)
18529
+ .add("datetime", normalizeDateTime)
18530
+ .add("integer", (value) => toNumber(value, DEFAULT_LOCALE))
18531
+ .add("boolean", (value) => toBoolean(value))
18532
+ .add("char", (value) => toString(value));
18505
18533
 
18506
18534
  /**
18507
18535
  * Get the pivot ID from the formula pivot ID.
@@ -18578,7 +18606,6 @@ const ADDRESS = {
18578
18606
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18579
18607
  arg("sheet (string, optional)", _t("A string indicating the name of the sheet into which the address points.")),
18580
18608
  ],
18581
- returns: ["STRING"],
18582
18609
  compute: function (row, column, absoluteRelativeMode = { value: DEFAULT_ABSOLUTE_RELATIVE_MODE }, useA1Notation = { value: true }, sheet) {
18583
18610
  const rowNumber = strictToInteger(row, this.locale);
18584
18611
  const colNumber = strictToInteger(column, this.locale);
@@ -18615,7 +18642,6 @@ const COLUMN = {
18615
18642
  args: [
18616
18643
  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.")),
18617
18644
  ],
18618
- returns: ["NUMBER"],
18619
18645
  compute: function (cellReference) {
18620
18646
  if (isEvaluationError(cellReference?.value)) {
18621
18647
  throw cellReference;
@@ -18633,7 +18659,6 @@ const COLUMN = {
18633
18659
  const COLUMNS = {
18634
18660
  description: _t("Number of columns in a specified array or range."),
18635
18661
  args: [arg("range (meta)", _t("The range whose column count will be returned."))],
18636
- returns: ["NUMBER"],
18637
18662
  compute: function (range) {
18638
18663
  if (isEvaluationError(range?.value)) {
18639
18664
  throw range;
@@ -18654,7 +18679,6 @@ const HLOOKUP = {
18654
18679
  arg("index (number)", _t("The row index of the value to be returned, where the first row in range is numbered 1.")),
18655
18680
  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.")),
18656
18681
  ],
18657
- returns: ["ANY"],
18658
18682
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18659
18683
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18660
18684
  assert(() => 1 <= _index && _index <= range[0].length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18684,7 +18708,6 @@ const INDEX = {
18684
18708
  arg("row (number, default=0)", _t("The index of the row to be returned from within the reference range of cells.")),
18685
18709
  arg("column (number, default=0)", _t("The index of the column to be returned from within the reference range of cells.")),
18686
18710
  ],
18687
- returns: ["ANY"],
18688
18711
  compute: function (reference, row = { value: 0 }, column = { value: 0 }) {
18689
18712
  const _reference = toMatrix(reference);
18690
18713
  const _row = toNumber(row.value, this.locale);
@@ -18715,7 +18738,6 @@ const INDIRECT = {
18715
18738
  arg("reference (string)", _t("The range of cells from which the values are returned.")),
18716
18739
  arg("use_a1_notation (boolean, default=TRUE)", _t("A boolean indicating whether to use A1 style notation (TRUE) or R1C1 style notation (FALSE).")),
18717
18740
  ],
18718
- returns: ["ANY"],
18719
18741
  compute: function (reference, useA1Notation = { value: true }) {
18720
18742
  let _reference = reference?.value?.toString();
18721
18743
  if (!_reference) {
@@ -18770,7 +18792,6 @@ const LOOKUP = {
18770
18792
  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.")),
18771
18793
  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.")),
18772
18794
  ],
18773
- returns: ["ANY"],
18774
18795
  compute: function (searchKey, searchArray, resultRange) {
18775
18796
  let nbCol = searchArray.length;
18776
18797
  let nbRow = searchArray[0].length;
@@ -18811,7 +18832,6 @@ const MATCH = {
18811
18832
  arg("range (any, range)", _t("The one-dimensional array to be searched.")),
18812
18833
  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.")),
18813
18834
  ],
18814
- returns: ["NUMBER"],
18815
18835
  compute: function (searchKey, range, searchType = { value: DEFAULT_SEARCH_TYPE }) {
18816
18836
  let _searchType = toNumber(searchType, this.locale);
18817
18837
  const nbCol = range.length;
@@ -18850,7 +18870,6 @@ const ROW = {
18850
18870
  args: [
18851
18871
  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.")),
18852
18872
  ],
18853
- returns: ["NUMBER"],
18854
18873
  compute: function (cellReference) {
18855
18874
  if (isEvaluationError(cellReference?.value)) {
18856
18875
  throw cellReference;
@@ -18868,7 +18887,6 @@ const ROW = {
18868
18887
  const ROWS = {
18869
18888
  description: _t("Number of rows in a specified array or range."),
18870
18889
  args: [arg("range (meta)", _t("The range whose row count will be returned."))],
18871
- returns: ["NUMBER"],
18872
18890
  compute: function (range) {
18873
18891
  if (isEvaluationError(range?.value)) {
18874
18892
  throw range;
@@ -18889,7 +18907,6 @@ const VLOOKUP = {
18889
18907
  arg("index (number)", _t("The column index of the value to be returned, where the first column in range is numbered 1.")),
18890
18908
  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.")),
18891
18909
  ],
18892
- returns: ["ANY"],
18893
18910
  compute: function (searchKey, range, index, isSorted = { value: DEFAULT_IS_SORTED }) {
18894
18911
  const _index = Math.trunc(toNumber(index?.value, this.locale));
18895
18912
  assert(() => 1 <= _index && _index <= range.length, _t("[[FUNCTION_NAME]] evaluates to an out of bounds range."));
@@ -18935,7 +18952,6 @@ const XLOOKUP = {
18935
18952
  (-2) Perform a binary search that relies on lookup_array being sorted in descending order. If not sorted, invalid results will be returned.\
18936
18953
  ")),
18937
18954
  ],
18938
- returns: ["ANY"],
18939
18955
  compute: function (searchKey, lookupRange, returnRange, defaultValue, matchMode = { value: DEFAULT_MATCH_MODE }, searchMode = { value: DEFAULT_SEARCH_MODE }) {
18940
18956
  const _matchMode = Math.trunc(toNumber(matchMode.value, this.locale));
18941
18957
  const _searchMode = Math.trunc(toNumber(searchMode.value, this.locale));
@@ -18991,12 +19007,6 @@ const PIVOT_VALUE = {
18991
19007
  assertDomainLength(_domainArgs);
18992
19008
  const pivot = this.getters.getPivot(pivotId);
18993
19009
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
18994
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
18995
- return {
18996
- value: CellErrorType.GenericError,
18997
- message: _t("This pivot does not support PIVOT.VALUE formula"),
18998
- };
18999
- }
19000
19010
  addPivotDependencies(this, coreDefinition);
19001
19011
  const error = pivot.assertIsValid({ throwOnError: false });
19002
19012
  if (error) {
@@ -19012,7 +19022,6 @@ const PIVOT_VALUE = {
19012
19022
  }
19013
19023
  return { value, format };
19014
19024
  },
19015
- returns: ["NUMBER", "STRING"],
19016
19025
  };
19017
19026
  const PIVOT_HEADER = {
19018
19027
  description: _t("Get the header of a pivot."),
@@ -19028,12 +19037,6 @@ const PIVOT_HEADER = {
19028
19037
  assertDomainLength(_domainArgs);
19029
19038
  const pivot = this.getters.getPivot(_pivotId);
19030
19039
  const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
19031
- if (!supportedPivotExplodedFormulaRegistry.get(coreDefinition.type)) {
19032
- return {
19033
- value: CellErrorType.GenericError,
19034
- message: _t("This pivot does not support PIVOT.VALUE formula"),
19035
- };
19036
- }
19037
19040
  addPivotDependencies(this, coreDefinition);
19038
19041
  const error = pivot.assertIsValid({ throwOnError: false });
19039
19042
  if (error) {
@@ -19058,7 +19061,6 @@ const PIVOT_HEADER = {
19058
19061
  : format,
19059
19062
  };
19060
19063
  },
19061
- returns: ["NUMBER", "STRING"],
19062
19064
  };
19063
19065
  const PIVOT = {
19064
19066
  description: _t("Get a pivot table."),
@@ -19125,7 +19127,6 @@ const PIVOT = {
19125
19127
  }
19126
19128
  return result;
19127
19129
  },
19128
- returns: ["RANGE<ANY>"],
19129
19130
  };
19130
19131
 
19131
19132
  var lookup = /*#__PURE__*/Object.freeze({
@@ -19156,7 +19157,6 @@ const ADD = {
19156
19157
  arg("value1 (number)", _t("The first addend.")),
19157
19158
  arg("value2 (number)", _t("The second addend.")),
19158
19159
  ],
19159
- returns: ["NUMBER"],
19160
19160
  compute: function (value1, value2) {
19161
19161
  return {
19162
19162
  value: toNumber(value1, this.locale) + toNumber(value2, this.locale),
@@ -19173,7 +19173,6 @@ const CONCAT = {
19173
19173
  arg("value1 (string)", _t("The value to which value2 will be appended.")),
19174
19174
  arg("value2 (string)", _t("The value to append to value1.")),
19175
19175
  ],
19176
- returns: ["STRING"],
19177
19176
  compute: function (value1, value2) {
19178
19177
  return toString(value1) + toString(value2);
19179
19178
  },
@@ -19188,7 +19187,6 @@ const DIVIDE = {
19188
19187
  arg("dividend (number)", _t("The number to be divided.")),
19189
19188
  arg("divisor (number)", _t("The number to divide by.")),
19190
19189
  ],
19191
- returns: ["NUMBER"],
19192
19190
  compute: function (dividend, divisor) {
19193
19191
  const _divisor = toNumber(divisor, this.locale);
19194
19192
  assert(() => _divisor !== 0, _t("The divisor must be different from zero."), CellErrorType.DivisionByZero);
@@ -19211,7 +19209,6 @@ const EQ = {
19211
19209
  arg("value1 (any)", _t("The first value.")),
19212
19210
  arg("value2 (any)", _t("The value to test against value1 for equality.")),
19213
19211
  ],
19214
- returns: ["BOOLEAN"],
19215
19212
  compute: function (value1, value2) {
19216
19213
  let _value1 = isEmpty(value1) ? getNeutral[typeof value2?.value] : value1?.value;
19217
19214
  let _value2 = isEmpty(value2) ? getNeutral[typeof value1?.value] : value2?.value;
@@ -19264,7 +19261,6 @@ const GT = {
19264
19261
  arg("value1 (any)", _t("The value to test as being greater than value2.")),
19265
19262
  arg("value2 (any)", _t("The second value.")),
19266
19263
  ],
19267
- returns: ["BOOLEAN"],
19268
19264
  compute: function (value1, value2) {
19269
19265
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19270
19266
  return v1 > v2;
@@ -19280,7 +19276,6 @@ const GTE = {
19280
19276
  arg("value1 (any)", _t("The value to test as being greater than or equal to value2.")),
19281
19277
  arg("value2 (any)", _t("The second value.")),
19282
19278
  ],
19283
- returns: ["BOOLEAN"],
19284
19279
  compute: function (value1, value2) {
19285
19280
  return applyRelationalOperator(value1, value2, (v1, v2) => {
19286
19281
  return v1 >= v2;
@@ -19296,7 +19291,6 @@ const LT = {
19296
19291
  arg("value1 (any)", _t("The value to test as being less than value2.")),
19297
19292
  arg("value2 (any)", _t("The second value.")),
19298
19293
  ],
19299
- returns: ["BOOLEAN"],
19300
19294
  compute: function (value1, value2) {
19301
19295
  return !GTE.compute.bind(this)(value1, value2);
19302
19296
  },
@@ -19310,7 +19304,6 @@ const LTE = {
19310
19304
  arg("value1 (any)", _t("The value to test as being less than or equal to value2.")),
19311
19305
  arg("value2 (any)", _t("The second value.")),
19312
19306
  ],
19313
- returns: ["BOOLEAN"],
19314
19307
  compute: function (value1, value2) {
19315
19308
  return !GT.compute.bind(this)(value1, value2);
19316
19309
  },
@@ -19324,7 +19317,6 @@ const MINUS = {
19324
19317
  arg("value1 (number)", _t("The minuend, or number to be subtracted from.")),
19325
19318
  arg("value2 (number)", _t("The subtrahend, or number to subtract from value1.")),
19326
19319
  ],
19327
- returns: ["NUMBER"],
19328
19320
  compute: function (value1, value2) {
19329
19321
  return {
19330
19322
  value: toNumber(value1, this.locale) - toNumber(value2, this.locale),
@@ -19341,7 +19333,6 @@ const MULTIPLY = {
19341
19333
  arg("factor1 (number)", _t("The first multiplicand.")),
19342
19334
  arg("factor2 (number)", _t("The second multiplicand.")),
19343
19335
  ],
19344
- returns: ["NUMBER"],
19345
19336
  compute: function (factor1, factor2) {
19346
19337
  return {
19347
19338
  value: toNumber(factor1, this.locale) * toNumber(factor2, this.locale),
@@ -19358,7 +19349,6 @@ const NE = {
19358
19349
  arg("value1 (any)", _t("The first value.")),
19359
19350
  arg("value2 (any)", _t("The value to test against value1 for inequality.")),
19360
19351
  ],
19361
- returns: ["BOOLEAN"],
19362
19352
  compute: function (value1, value2) {
19363
19353
  return !EQ.compute.bind(this)(value1, value2);
19364
19354
  },
@@ -19372,7 +19362,6 @@ const POW = {
19372
19362
  arg("base (number)", _t("The number to raise to the exponent power.")),
19373
19363
  arg("exponent (number)", _t("The exponent to raise base to.")),
19374
19364
  ],
19375
- returns: ["NUMBER"],
19376
19365
  compute: function (base, exponent) {
19377
19366
  return POWER.compute.bind(this)(base, exponent);
19378
19367
  },
@@ -19385,7 +19374,6 @@ const UMINUS = {
19385
19374
  args: [
19386
19375
  arg("value (number)", _t("The number to have its sign reversed. Equivalently, the number to multiply by -1.")),
19387
19376
  ],
19388
- returns: ["NUMBER"],
19389
19377
  compute: function (value) {
19390
19378
  return {
19391
19379
  value: -toNumber(value, this.locale),
@@ -19399,7 +19387,6 @@ const UMINUS = {
19399
19387
  const UNARY_PERCENT = {
19400
19388
  description: _t("Value interpreted as a percentage."),
19401
19389
  args: [arg("percentage (number)", _t("The value to interpret as a percentage."))],
19402
- returns: ["NUMBER"],
19403
19390
  compute: function (percentage) {
19404
19391
  return toNumber(percentage, this.locale) / 100;
19405
19392
  },
@@ -19410,7 +19397,6 @@ const UNARY_PERCENT = {
19410
19397
  const UPLUS = {
19411
19398
  description: _t("A specified number, unchanged."),
19412
19399
  args: [arg("value (any)", _t("The number to return."))],
19413
- returns: ["ANY"],
19414
19400
  compute: function (value = { value: null }) {
19415
19401
  return value;
19416
19402
  },
@@ -19446,7 +19432,6 @@ const CHAR = {
19446
19432
  args: [
19447
19433
  arg("table_number (number)", _t("The number of the character to look up from the current Unicode table in decimal format.")),
19448
19434
  ],
19449
- returns: ["STRING"],
19450
19435
  compute: function (tableNumber) {
19451
19436
  const _tableNumber = Math.trunc(toNumber(tableNumber, this.locale));
19452
19437
  assert(() => _tableNumber >= 1, _t("The table_number (%s) is out of range.", _tableNumber.toString()));
@@ -19460,7 +19445,6 @@ const CHAR = {
19460
19445
  const CLEAN = {
19461
19446
  description: _t("Remove non-printable characters from a piece of text."),
19462
19447
  args: [arg("text (string)", _t("The text whose non-printable characters are to be removed."))],
19463
- returns: ["STRING"],
19464
19448
  compute: function (text) {
19465
19449
  const _text = toString(text);
19466
19450
  let cleanedStr = "";
@@ -19482,7 +19466,6 @@ const CONCATENATE = {
19482
19466
  arg("string1 (string, range<string>)", _t("The initial string.")),
19483
19467
  arg("string2 (string, range<string>, repeating)", _t("More strings to append in sequence.")),
19484
19468
  ],
19485
- returns: ["STRING"],
19486
19469
  compute: function (...datas) {
19487
19470
  return reduceAny(datas, (acc, a) => acc + toString(a), "");
19488
19471
  },
@@ -19497,7 +19480,6 @@ const EXACT = {
19497
19480
  arg("string1 (string)", _t("The first string to compare.")),
19498
19481
  arg("string2 (string)", _t("The second string to compare.")),
19499
19482
  ],
19500
- returns: ["BOOLEAN"],
19501
19483
  compute: function (string1, string2) {
19502
19484
  return toString(string1) === toString(string2);
19503
19485
  },
@@ -19513,7 +19495,6 @@ const FIND = {
19513
19495
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19514
19496
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19515
19497
  ],
19516
- returns: ["NUMBER"],
19517
19498
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19518
19499
  const _searchFor = toString(searchFor);
19519
19500
  const _textToSearch = toString(textToSearch);
@@ -19536,7 +19517,6 @@ const JOIN = {
19536
19517
  arg("value_or_array1 (string, range<string>)", _t("The value or values to be appended using delimiter.")),
19537
19518
  arg("value_or_array2 (string, range<string>, repeating)", _t("More values to be appended using delimiter.")),
19538
19519
  ],
19539
- returns: ["STRING"],
19540
19520
  compute: function (delimiter, ...valuesOrArrays) {
19541
19521
  const _delimiter = toString(delimiter);
19542
19522
  return reduceAny(valuesOrArrays, (acc, a) => (acc ? acc + _delimiter : "") + toString(a), "");
@@ -19551,7 +19531,6 @@ const LEFT = {
19551
19531
  arg("text (string)", _t("The string from which the left portion will be returned.")),
19552
19532
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the left side of string.")),
19553
19533
  ],
19554
- returns: ["STRING"],
19555
19534
  compute: function (text, ...args) {
19556
19535
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19557
19536
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19565,7 +19544,6 @@ const LEFT = {
19565
19544
  const LEN = {
19566
19545
  description: _t("Length of a string."),
19567
19546
  args: [arg("text (string)", _t("The string whose length will be returned."))],
19568
- returns: ["NUMBER"],
19569
19547
  compute: function (text) {
19570
19548
  return toString(text).length;
19571
19549
  },
@@ -19577,7 +19555,6 @@ const LEN = {
19577
19555
  const LOWER = {
19578
19556
  description: _t("Converts a specified string to lowercase."),
19579
19557
  args: [arg("text (string)", _t("The string to convert to lowercase."))],
19580
- returns: ["STRING"],
19581
19558
  compute: function (text) {
19582
19559
  return toString(text).toLowerCase();
19583
19560
  },
@@ -19593,7 +19570,6 @@ const MID = {
19593
19570
  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.")),
19594
19571
  arg("extract_length (number)", _t("The length of the segment to extract.")),
19595
19572
  ],
19596
- returns: ["STRING"],
19597
19573
  compute: function (text, starting_at, extract_length) {
19598
19574
  const _text = toString(text);
19599
19575
  const _starting_at = toNumber(starting_at, this.locale);
@@ -19612,7 +19588,6 @@ const PROPER = {
19612
19588
  args: [
19613
19589
  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.")),
19614
19590
  ],
19615
- returns: ["STRING"],
19616
19591
  compute: function (text) {
19617
19592
  const _text = toString(text);
19618
19593
  return _text.replace(wordRegex, (word) => {
@@ -19632,7 +19607,6 @@ const REPLACE = {
19632
19607
  arg("length (number)", _t("The number of characters in the text to be replaced.")),
19633
19608
  arg("new_text (string)", _t("The text which will be inserted into the original text.")),
19634
19609
  ],
19635
- returns: ["STRING"],
19636
19610
  compute: function (text, position, length, newText) {
19637
19611
  const _position = toNumber(position, this.locale);
19638
19612
  assert(() => _position >= 1, _t("The position (%s) must be greater than or equal to 1.", _position.toString()));
@@ -19652,7 +19626,6 @@ const RIGHT = {
19652
19626
  arg("text (string)", _t("The string from which the right portion will be returned.")),
19653
19627
  arg("number_of_characters (number, optional)", _t("The number of characters to return from the right side of string.")),
19654
19628
  ],
19655
- returns: ["STRING"],
19656
19629
  compute: function (text, ...args) {
19657
19630
  const _numberOfCharacters = args.length ? toNumber(args[0], this.locale) : 1;
19658
19631
  assert(() => _numberOfCharacters >= 0, _t("The number_of_characters (%s) must be positive or null.", _numberOfCharacters.toString()));
@@ -19672,7 +19645,6 @@ const SEARCH = {
19672
19645
  arg("text_to_search (string)", _t("The text to search for the first occurrence of search_for.")),
19673
19646
  arg(`starting_at (number, default=${DEFAULT_STARTING_AT})`, _t("The character within text_to_search at which to start the search.")),
19674
19647
  ],
19675
- returns: ["NUMBER"],
19676
19648
  compute: function (searchFor, textToSearch, startingAt = { value: DEFAULT_STARTING_AT }) {
19677
19649
  const _searchFor = toString(searchFor).toLowerCase();
19678
19650
  const _textToSearch = toString(textToSearch).toLowerCase();
@@ -19699,7 +19671,6 @@ const SPLIT = {
19699
19671
  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 \
19700
19672
  consecutive delimiters as one (if TRUE). If FALSE, empty cells values are added between consecutive delimiters.")),
19701
19673
  ],
19702
- returns: ["RANGE<STRING>"],
19703
19674
  compute: function (text, delimiter, splitByEach = { value: SPLIT_DEFAULT_SPLIT_BY_EACH }, removeEmptyText = { value: SPLIT_DEFAULT_REMOVE_EMPTY_TEXT }) {
19704
19675
  const _text = toString(text);
19705
19676
  const _delimiter = escapeRegExp(toString(delimiter));
@@ -19726,7 +19697,6 @@ const SUBSTITUTE = {
19726
19697
  arg("replace_with (string)", _t("The string that will replace search_for.")),
19727
19698
  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.")),
19728
19699
  ],
19729
- returns: ["NUMBER"],
19730
19700
  compute: function (textToSearch, searchFor, replaceWith, occurrenceNumber) {
19731
19701
  const _occurrenceNumber = toNumber(occurrenceNumber, this.locale);
19732
19702
  assert(() => _occurrenceNumber >= 0, _t("The occurrenceNumber (%s) must be positive or null.", _occurrenceNumber.toString()));
@@ -19756,7 +19726,6 @@ const TEXTJOIN = {
19756
19726
  arg("text1 (string, range<string>)", _t("Any text item. This could be a string, or an array of strings in a range.")),
19757
19727
  arg("text2 (string, range<string>, repeating)", _t("Additional text item(s).")),
19758
19728
  ],
19759
- returns: ["STRING"],
19760
19729
  compute: function (delimiter, ignoreEmpty, ...textsOrArrays) {
19761
19730
  const _delimiter = toString(delimiter);
19762
19731
  const _ignoreEmpty = toBoolean(ignoreEmpty);
@@ -19773,7 +19742,6 @@ const TRIM = {
19773
19742
  args: [
19774
19743
  arg("text (string)", _t("The text or reference to a cell containing text to be trimmed.")),
19775
19744
  ],
19776
- returns: ["STRING"],
19777
19745
  compute: function (text) {
19778
19746
  return trimContent(toString(text));
19779
19747
  },
@@ -19785,7 +19753,6 @@ const TRIM = {
19785
19753
  const UPPER = {
19786
19754
  description: _t("Converts a specified string to uppercase."),
19787
19755
  args: [arg("text (string)", _t("The string to convert to uppercase."))],
19788
- returns: ["STRING"],
19789
19756
  compute: function (text) {
19790
19757
  return toString(text).toUpperCase();
19791
19758
  },
@@ -19800,7 +19767,6 @@ const TEXT = {
19800
19767
  arg("number (number)", _t("The number, date or time to format.")),
19801
19768
  arg("format (string)", _t("The pattern by which to format the number, enclosed in quotation marks.")),
19802
19769
  ],
19803
- returns: ["STRING"],
19804
19770
  compute: function (number, format) {
19805
19771
  const _number = toNumber(number, this.locale);
19806
19772
  return formatValue(_number, { format: toString(format), locale: this.locale });
@@ -19841,7 +19807,6 @@ const HYPERLINK = {
19841
19807
  arg("url (string)", _t("The full URL of the link enclosed in quotation marks.")),
19842
19808
  arg("link_label (string, optional)", _t("The text to display in the cell, enclosed in quotation marks.")),
19843
19809
  ],
19844
- returns: ["STRING"],
19845
19810
  compute: function (url, linkLabel) {
19846
19811
  const processedUrl = toString(url).trim();
19847
19812
  const processedLabel = toString(linkLabel) || processedUrl;
@@ -19900,6 +19865,9 @@ function addInputHandling(descr) {
19900
19865
  }
19901
19866
  args[i] = arg[0][0];
19902
19867
  }
19868
+ if (!isMatrix(arg) && argDefinition.acceptMatrixOnly) {
19869
+ throw new BadExpressionError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be reference to a cell or range.", (i + 1).toString()));
19870
+ }
19903
19871
  }
19904
19872
  return descr.compute.apply(this, args);
19905
19873
  }
@@ -21494,12 +21462,6 @@ function compileTokens(tokens) {
21494
21462
  // detect when an argument need to be evaluated as a meta argument
21495
21463
  const isMeta = argTypes.includes("META");
21496
21464
  const hasRange = argTypes.some((t) => isRangeType(t));
21497
- const isRangeOnly = argTypes.every((t) => isRangeType(t));
21498
- if (isRangeOnly) {
21499
- if (!isRangeInput(currentArg)) {
21500
- 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 }));
21501
- }
21502
- }
21503
21465
  compiledArgs.push(compileAST(currentArg, isMeta, hasRange));
21504
21466
  }
21505
21467
  return compiledArgs;
@@ -21664,16 +21626,6 @@ function assertEnoughArgs(ast) {
21664
21626
  function isRangeType(type) {
21665
21627
  return type.startsWith("RANGE");
21666
21628
  }
21667
- function isRangeInput(arg) {
21668
- if (arg.type === "REFERENCE") {
21669
- return true;
21670
- }
21671
- if (arg.type === "FUNCALL") {
21672
- const fnDef = functions$1[arg.value.toUpperCase()];
21673
- return fnDef && isRangeType(fnDef.returns[0]);
21674
- }
21675
- return false;
21676
- }
21677
21629
 
21678
21630
  const functions = functionRegistry.content;
21679
21631
  function isExportableToExcel(tokens) {
@@ -21717,11 +21669,14 @@ const PIVOT_FUNCTIONS = ["PIVOT.VALUE", "PIVOT.HEADER", "PIVOT"];
21717
21669
  function makeFieldProposal(field, granularity) {
21718
21670
  const groupBy = granularity ? `${field.name}:${granularity}` : field.name;
21719
21671
  const quotedGroupBy = `"${groupBy}"`;
21672
+ const fuzzySearchKey = field.string !== field.name
21673
+ ? field.string + quotedGroupBy // search on translated name and on technical name
21674
+ : quotedGroupBy;
21720
21675
  return {
21721
21676
  text: quotedGroupBy,
21722
21677
  description: field.string + (field.help ? ` (${field.help})` : ""),
21723
21678
  htmlContent: [{ value: quotedGroupBy, color: tokenColors.STRING }],
21724
- fuzzySearchKey: field.string + quotedGroupBy, // search on translated name and on technical name
21679
+ fuzzySearchKey,
21725
21680
  };
21726
21681
  }
21727
21682
  /**
@@ -21781,6 +21736,14 @@ function getNumberOfPivotFunctions(tokens) {
21781
21736
  return getFunctionsFromTokens(tokens, PIVOT_FUNCTIONS).length;
21782
21737
  }
21783
21738
 
21739
+ /**
21740
+ * Registry to enable or disable the support of positional arguments
21741
+ * (with a leading #) in pivot functions
21742
+ * e.g. =PIVOT.VALUE(1,"probability","#stage",1)
21743
+ */
21744
+ const supportedPivotPositionalFormulaRegistry = new Registry();
21745
+ supportedPivotPositionalFormulaRegistry.add("SPREADSHEET", false);
21746
+
21784
21747
  autoCompleteProviders.add("pivot_ids", {
21785
21748
  sequence: 50,
21786
21749
  autoSelectFirstProposal: true,
@@ -21799,10 +21762,6 @@ autoCompleteProviders.add("pivot_ids", {
21799
21762
  return pivotIds
21800
21763
  .map((pivotId) => {
21801
21764
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21802
- if (functionContext.parent.toUpperCase() !== "PIVOT" &&
21803
- !supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21804
- return undefined;
21805
- }
21806
21765
  const formulaId = this.getters.getPivotFormulaId(pivotId);
21807
21766
  const str = `${formulaId}`;
21808
21767
  return {
@@ -21830,15 +21789,13 @@ autoCompleteProviders.add("pivot_measures", {
21830
21789
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21831
21790
  return [];
21832
21791
  }
21833
- const dataSource = this.getters.getPivot(pivotId);
21834
- const fields = dataSource.getFields();
21792
+ const pivot = this.getters.getPivot(pivotId);
21793
+ pivot.init();
21794
+ const fields = pivot.getFields();
21835
21795
  if (!fields) {
21836
21796
  return [];
21837
21797
  }
21838
21798
  const definition = this.getters.getPivotCoreDefinition(pivotId);
21839
- if (!supportedPivotExplodedFormulaRegistry.get(definition.type)) {
21840
- return [];
21841
- }
21842
21799
  return definition.measures
21843
21800
  .map((measure) => {
21844
21801
  if (measure.name === "__count") {
@@ -21874,16 +21831,13 @@ autoCompleteProviders.add("pivot_group_fields", {
21874
21831
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21875
21832
  return;
21876
21833
  }
21877
- const dataSource = this.getters.getPivot(pivotId);
21878
- const fields = dataSource.getFields();
21834
+ const pivot = this.getters.getPivot(pivotId);
21835
+ pivot.init();
21836
+ const fields = pivot.getFields();
21879
21837
  if (!fields) {
21880
21838
  return;
21881
21839
  }
21882
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21883
- const { columns, rows } = dataSource.definition;
21884
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21885
- return [];
21886
- }
21840
+ const { columns, rows } = pivot.definition;
21887
21841
  let args = functionContext.args;
21888
21842
  if (functionContext?.parent.toUpperCase() === "PIVOT.VALUE") {
21889
21843
  args = args.filter((ast, index) => index % 2 === 0); // keep only the field names
@@ -21920,6 +21874,9 @@ autoCompleteProviders.add("pivot_group_fields", {
21920
21874
  return field ? makeFieldProposal(field, granularity) : undefined;
21921
21875
  })
21922
21876
  .concat(groupBys.map((groupBy) => {
21877
+ if (!supportedPivotPositionalFormulaRegistry.get(pivot.type)) {
21878
+ return undefined;
21879
+ }
21923
21880
  const fieldName = groupBy.split(":")[0];
21924
21881
  const field = fields[fieldName];
21925
21882
  if (!field) {
@@ -21968,12 +21925,8 @@ autoCompleteProviders.add("pivot_group_values", {
21968
21925
  if (!pivotId || !this.getters.isExistingPivot(pivotId)) {
21969
21926
  return;
21970
21927
  }
21971
- const { type } = this.getters.getPivotCoreDefinition(pivotId);
21972
- if (!supportedPivotExplodedFormulaRegistry.get(type)) {
21973
- return [];
21974
- }
21975
- const dataSource = this.getters.getPivot(pivotId);
21976
- if (!dataSource.isValid()) {
21928
+ const pivot = this.getters.getPivot(pivotId);
21929
+ if (!pivot.isValid()) {
21977
21930
  return;
21978
21931
  }
21979
21932
  const argPosition = functionContext.argPosition;
@@ -21981,7 +21934,46 @@ autoCompleteProviders.add("pivot_group_values", {
21981
21934
  if (!groupByField) {
21982
21935
  return;
21983
21936
  }
21984
- return dataSource.getPossibleFieldValues(groupByField.split(":")[0]).map(({ value, label }) => {
21937
+ let dimension;
21938
+ try {
21939
+ dimension = pivot.definition.getDimension(groupByField);
21940
+ }
21941
+ catch (error) {
21942
+ return undefined;
21943
+ }
21944
+ if (dimension.granularity === "month_number") {
21945
+ return Object.values(MONTHS).map((monthDisplayName, index) => ({
21946
+ text: `${index + 1}`,
21947
+ fuzzySearchKey: monthDisplayName.toString(),
21948
+ description: monthDisplayName.toString(),
21949
+ htmlContent: [{ value: `${index + 1}`, color: tokenColors.NUMBER }],
21950
+ }));
21951
+ }
21952
+ else if (dimension.granularity === "quarter_number") {
21953
+ return [1, 2, 3, 4].map((quarter) => ({
21954
+ text: `${quarter}`,
21955
+ fuzzySearchKey: `${quarter}`,
21956
+ description: _t("Quarter %s", quarter),
21957
+ htmlContent: [{ value: `${quarter}`, color: tokenColors.NUMBER }],
21958
+ }));
21959
+ }
21960
+ else if (dimension.granularity === "day_of_month") {
21961
+ return range(1, 32).map((dayOfMonth) => ({
21962
+ text: `${dayOfMonth}`,
21963
+ fuzzySearchKey: `${dayOfMonth}`,
21964
+ description: "",
21965
+ htmlContent: [{ value: `${dayOfMonth}`, color: tokenColors.NUMBER }],
21966
+ }));
21967
+ }
21968
+ else if (dimension.granularity === "iso_week_number") {
21969
+ return range(0, 54).map((isoWeekNumber) => ({
21970
+ text: `${isoWeekNumber}`,
21971
+ fuzzySearchKey: `${isoWeekNumber}`,
21972
+ description: "",
21973
+ htmlContent: [{ value: `${isoWeekNumber}`, color: tokenColors.NUMBER }],
21974
+ }));
21975
+ }
21976
+ return pivot.getPossibleFieldValues(dimension).map(({ value, label }) => {
21985
21977
  const isString = typeof value === "string";
21986
21978
  const text = isString ? `"${value}"` : value.toString();
21987
21979
  const color = isString ? tokenColors.STRING : tokenColors.NUMBER;
@@ -22088,7 +22080,9 @@ autofillModifiersRegistry
22088
22080
  tooltip: content
22089
22081
  ? {
22090
22082
  props: {
22091
- content: evaluateLiteral(data.cell?.content, localeFormat).formattedValue,
22083
+ content: data.cell
22084
+ ? evaluateLiteral(data.cell, localeFormat).formattedValue
22085
+ : "",
22092
22086
  },
22093
22087
  }
22094
22088
  : undefined,
@@ -22151,9 +22145,7 @@ function getGroup(cell, cells, filter) {
22151
22145
  if (x === cell) {
22152
22146
  found = true;
22153
22147
  }
22154
- const cellValue = x?.isFormula
22155
- ? undefined
22156
- : evaluateLiteral(x?.content, { locale: DEFAULT_LOCALE });
22148
+ const cellValue = x === undefined || x.isFormula ? undefined : evaluateLiteral(x, { locale: DEFAULT_LOCALE });
22157
22149
  if (cellValue && filter(cellValue)) {
22158
22150
  group.push(cellValue);
22159
22151
  }
@@ -22201,7 +22193,7 @@ autofillRulesRegistry
22201
22193
  })
22202
22194
  .add("increment_alphanumeric_value", {
22203
22195
  condition: (cell) => !cell.isFormula &&
22204
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22196
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text &&
22205
22197
  alphaNumericValueRegExp.test(cell.content),
22206
22198
  generateRule: (cell, cells) => {
22207
22199
  const numberPostfix = parseInt(cell.content.match(numberPostfixRegExp)[0]);
@@ -22224,7 +22216,7 @@ autofillRulesRegistry
22224
22216
  })
22225
22217
  .add("copy_text", {
22226
22218
  condition: (cell) => !cell.isFormula &&
22227
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22219
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.text,
22228
22220
  generateRule: () => {
22229
22221
  return { type: "COPY_MODIFIER" };
22230
22222
  },
@@ -22239,11 +22231,11 @@ autofillRulesRegistry
22239
22231
  })
22240
22232
  .add("increment_number", {
22241
22233
  condition: (cell) => !cell.isFormula &&
22242
- evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22234
+ evaluateLiteral(cell, { locale: DEFAULT_LOCALE }).type === CellValueType.number,
22243
22235
  generateRule: (cell, cells) => {
22244
22236
  const group = getGroup(cell, cells, (evaluatedCell) => evaluatedCell.type === CellValueType.number).map((cell) => Number(cell.value));
22245
22237
  const increment = calculateIncrementBasedOnGroup(group);
22246
- const evaluation = evaluateLiteral(cell.content, { locale: DEFAULT_LOCALE });
22238
+ const evaluation = evaluateLiteral(cell, { locale: DEFAULT_LOCALE });
22247
22239
  return {
22248
22240
  type: "INCREMENT_MODIFIER",
22249
22241
  increment,
@@ -25467,7 +25459,7 @@ class Popover extends Component {
25467
25459
  if (!anchor)
25468
25460
  return;
25469
25461
  const propsMaxSize = { width: this.props.maxWidth, height: this.props.maxHeight };
25470
- const elDims = {
25462
+ let elDims = {
25471
25463
  width: el.getBoundingClientRect().width,
25472
25464
  height: el.getBoundingClientRect().height,
25473
25465
  };
@@ -25475,7 +25467,14 @@ class Popover extends Component {
25475
25467
  const popoverPositionHelper = this.props.positioning === "BottomLeft"
25476
25468
  ? new BottomLeftPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect)
25477
25469
  : new TopRightPopoverContext(anchor, this.containerRect, propsMaxSize, spreadsheetRect);
25478
- const style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25470
+ el.style["max-height"] = popoverPositionHelper.getMaxHeight(elDims.height) + "px";
25471
+ el.style["max-width"] = popoverPositionHelper.getMaxWidth(elDims.width) + "px";
25472
+ // Re-compute the dimensions after setting the max-width and max-height
25473
+ elDims = {
25474
+ width: el.getBoundingClientRect().width,
25475
+ height: el.getBoundingClientRect().height,
25476
+ };
25477
+ let style = popoverPositionHelper.getCss(elDims, this.props.verticalOffset);
25479
25478
  for (const property of Object.keys(style)) {
25480
25479
  el.style[property] = style[property];
25481
25480
  }
@@ -25538,8 +25537,6 @@ class PopoverPositionContext {
25538
25537
  const shouldRenderAtRight = this.shouldRenderAtRight(elDims.width);
25539
25538
  verticalOffset = shouldRenderAtBottom ? verticalOffset : -verticalOffset;
25540
25539
  const cssProperties = {
25541
- "max-height": maxHeight + "px",
25542
- "max-width": maxWidth + "px",
25543
25540
  top: this.getTopCoordinate(actualHeight, shouldRenderAtBottom) -
25544
25541
  this.spreadsheetOffset.y -
25545
25542
  verticalOffset +
@@ -31353,10 +31350,8 @@ class ChartTitle extends Component {
31353
31350
 
31354
31351
  class AxisDesignEditor extends Component {
31355
31352
  static template = "o-spreadsheet-AxisDesignEditor";
31356
- static components = {
31357
- Section,
31358
- ChartTitle,
31359
- };
31353
+ static components = { Section, ChartTitle };
31354
+ static props = { figureId: String, definition: Object, updateChart: Function, axesList: Array };
31360
31355
  state = useState({ currentAxis: "x" });
31361
31356
  get axisTitleStyle() {
31362
31357
  const axisDesign = this.props.definition.axesDesign?.[this.state.currentAxis] ?? {};
@@ -31507,6 +31502,12 @@ class ChartWithAxisDesignPanel extends Component {
31507
31502
  AxisDesignEditor,
31508
31503
  RoundColorPicker,
31509
31504
  };
31505
+ static props = {
31506
+ figureId: String,
31507
+ definition: Object,
31508
+ canUpdateChart: Function,
31509
+ updateChart: Function,
31510
+ };
31510
31511
  state = useState({ index: 0 });
31511
31512
  get axesList() {
31512
31513
  const { useLeftAxis, useRightAxis } = getDefinedAxis(this.props.definition);
@@ -31688,14 +31689,6 @@ class GaugeChartDesignPanel extends Component {
31688
31689
  const cancelledReasons = [...(this.state.sectionRuleDispatchResult?.reasons || [])];
31689
31690
  return cancelledReasons.map((error) => ChartTerms.Errors[error] || ChartTerms.Errors.Unexpected);
31690
31691
  }
31691
- updateBackgroundColor(color) {
31692
- this.props.updateChart(this.props.figureId, {
31693
- background: color,
31694
- });
31695
- }
31696
- updateTitle(content) {
31697
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31698
- }
31699
31692
  isRangeMinInvalid() {
31700
31693
  return !!(this.state.sectionRuleDispatchResult?.isCancelledBecause("EmptyGaugeRangeMin" /* CommandResult.EmptyGaugeRangeMin */) ||
31701
31694
  this.state.sectionRuleDispatchResult?.isCancelledBecause("GaugeRangeMinNaN" /* CommandResult.GaugeRangeMinNaN */) ||
@@ -31735,9 +31728,6 @@ class GaugeChartDesignPanel extends Component {
31735
31728
  sectionRule,
31736
31729
  });
31737
31730
  }
31738
- get backgroundColorTitle() {
31739
- return ChartTerms.BackgroundColor;
31740
- }
31741
31731
  }
31742
31732
 
31743
31733
  class LineConfigPanel extends GenericChartConfigPanel {
@@ -31920,9 +31910,6 @@ class ScorecardChartDesignPanel extends Component {
31920
31910
  get humanizeNumbersLabel() {
31921
31911
  return _t("Humanize numbers");
31922
31912
  }
31923
- updateTitle(content) {
31924
- this.props.updateChart(this.props.figureId, { title: { text: content } });
31925
- }
31926
31913
  updateHumanizeNumbers(humanize) {
31927
31914
  this.props.updateChart(this.props.figureId, { humanize });
31928
31915
  }
@@ -31945,9 +31932,6 @@ class ScorecardChartDesignPanel extends Component {
31945
31932
  break;
31946
31933
  }
31947
31934
  }
31948
- get backgroundColorTitle() {
31949
- return ChartTerms.BackgroundColor;
31950
- }
31951
31935
  }
31952
31936
 
31953
31937
  class WaterfallChartDesignPanel extends Component {
@@ -33451,13 +33435,17 @@ class SelectMenu extends Component {
33451
33435
  class: { type: String, optional: true },
33452
33436
  };
33453
33437
  static components = { Menu };
33438
+ menuId = new UuidGenerator().uuidv4();
33454
33439
  selectRef = useRef("select");
33455
33440
  selectRect = useAbsoluteBoundingRect(this.selectRef);
33456
33441
  state = useState({
33457
33442
  isMenuOpen: false,
33458
33443
  });
33459
- onClick() {
33460
- this.state.isMenuOpen = true;
33444
+ onClick(ev) {
33445
+ if (ev.closedMenuId === this.menuId) {
33446
+ return;
33447
+ }
33448
+ this.state.isMenuOpen = !this.state.isMenuOpen;
33461
33449
  }
33462
33450
  onMenuClosed() {
33463
33451
  this.state.isMenuOpen = false;
@@ -33465,7 +33453,7 @@ class SelectMenu extends Component {
33465
33453
  get menuPosition() {
33466
33454
  return {
33467
33455
  x: this.selectRect.x,
33468
- y: this.selectRect.y,
33456
+ y: this.selectRect.y + this.selectRect.height,
33469
33457
  };
33470
33458
  }
33471
33459
  }
@@ -34405,9 +34393,9 @@ class FindAndReplacePanel extends Component {
34405
34393
  static props = {
34406
34394
  onCloseSidePanel: Function,
34407
34395
  };
34408
- dataRange = "";
34409
34396
  searchInput = useRef("searchInput");
34410
34397
  store;
34398
+ state;
34411
34399
  get hasSearchResult() {
34412
34400
  return this.store.selectedMatchIndex !== null;
34413
34401
  }
@@ -34437,6 +34425,7 @@ class FindAndReplacePanel extends Component {
34437
34425
  }
34438
34426
  setup() {
34439
34427
  this.store = useLocalStore(FindAndReplaceStore);
34428
+ this.state = useState({ dataRange: "" });
34440
34429
  onMounted(() => this.searchInput.el?.focus());
34441
34430
  }
34442
34431
  onFocusSearch() {
@@ -34473,13 +34462,13 @@ class FindAndReplacePanel extends Component {
34473
34462
  this.store.updateSearchOptions({ searchScope });
34474
34463
  }
34475
34464
  onSearchRangeChanged(ranges) {
34476
- this.dataRange = ranges[0];
34465
+ this.state.dataRange = ranges[0];
34477
34466
  }
34478
34467
  updateDataRange() {
34479
- if (!this.dataRange || this.searchOptions.searchScope !== "specificRange") {
34468
+ if (!this.state.dataRange || this.searchOptions.searchScope !== "specificRange") {
34480
34469
  return;
34481
34470
  }
34482
- const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.dataRange);
34471
+ const specificRange = this.env.model.getters.getRangeFromSheetXC(this.env.model.getters.getActiveSheetId(), this.state.dataRange);
34483
34472
  this.store.updateSearchOptions({ specificRange });
34484
34473
  }
34485
34474
  }
@@ -34524,31 +34513,6 @@ class MoreFormatsPanel extends Component {
34524
34513
  }
34525
34514
  }
34526
34515
 
34527
- /** @odoo-module */
34528
- class EditableName extends Component {
34529
- static template = "o-spreadsheet-EditableName";
34530
- static props = {
34531
- name: String,
34532
- displayName: String,
34533
- onChanged: Function,
34534
- };
34535
- state;
34536
- setup() {
34537
- this.state = useState({
34538
- isEditing: false,
34539
- name: "",
34540
- });
34541
- }
34542
- rename() {
34543
- this.state.isEditing = true;
34544
- this.state.name = this.props.name;
34545
- }
34546
- save() {
34547
- this.props.onChanged(this.state.name.trim());
34548
- this.state.isEditing = false;
34549
- }
34550
- }
34551
-
34552
34516
  css /* scss */ `
34553
34517
  .pivot-defer-update {
34554
34518
  min-height: 35px;
@@ -34914,6 +34878,135 @@ class PivotLayoutConfigurator extends Component {
34914
34878
  }
34915
34879
  }
34916
34880
 
34881
+ css /* scss */ `
34882
+ .os-cog-wheel-menu-icon {
34883
+ cursor: pointer;
34884
+ }
34885
+
34886
+ .os-cog-wheel-menu {
34887
+ background: white;
34888
+ .btn-link {
34889
+ text-decoration: none;
34890
+ color: #017e84;
34891
+ font-weight: 500;
34892
+ &:hover {
34893
+ color: #01585c;
34894
+ }
34895
+ }
34896
+ }
34897
+ `;
34898
+ class CogWheelMenu extends Component {
34899
+ static template = "o-spreadsheet-CogWheelMenu";
34900
+ static components = { Popover };
34901
+ static props = {
34902
+ items: Array,
34903
+ };
34904
+ buttonRef = useRef("button");
34905
+ popover = useState({ isOpen: false });
34906
+ setup() {
34907
+ useExternalListener(window, "click", (ev) => {
34908
+ if (ev.target !== this.buttonRef.el) {
34909
+ this.popover.isOpen = false;
34910
+ }
34911
+ });
34912
+ }
34913
+ get popoverProps() {
34914
+ const { x, y, width, height } = this.buttonRef.el.getBoundingClientRect();
34915
+ return {
34916
+ anchorRect: { x, y, width, height },
34917
+ positioning: "BottomLeft",
34918
+ };
34919
+ }
34920
+ togglePopover() {
34921
+ this.popover.isOpen = !this.popover.isOpen;
34922
+ }
34923
+ }
34924
+
34925
+ /** @odoo-module */
34926
+ class EditableName extends Component {
34927
+ static template = "o-spreadsheet-EditableName";
34928
+ static props = {
34929
+ name: String,
34930
+ displayName: String,
34931
+ onChanged: Function,
34932
+ };
34933
+ state;
34934
+ setup() {
34935
+ this.state = useState({
34936
+ isEditing: false,
34937
+ name: "",
34938
+ });
34939
+ }
34940
+ rename() {
34941
+ this.state.isEditing = true;
34942
+ this.state.name = this.props.name;
34943
+ }
34944
+ save() {
34945
+ this.props.onChanged(this.state.name.trim());
34946
+ this.state.isEditing = false;
34947
+ }
34948
+ }
34949
+
34950
+ class PivotTitleSection extends Component {
34951
+ static template = "o-spreadsheet-PivotTitleSection";
34952
+ static components = { CogWheelMenu, Section, EditableName };
34953
+ static props = {
34954
+ pivotId: String,
34955
+ };
34956
+ get cogWheelMenuItems() {
34957
+ return [
34958
+ {
34959
+ name: "Duplicate",
34960
+ icon: "fa-copy",
34961
+ onClick: () => this.duplicatePivot(),
34962
+ },
34963
+ {
34964
+ name: "Delete",
34965
+ icon: "fa-trash",
34966
+ onClick: () => this.delete(),
34967
+ },
34968
+ ];
34969
+ }
34970
+ get name() {
34971
+ return this.env.model.getters.getPivotName(this.props.pivotId);
34972
+ }
34973
+ get displayName() {
34974
+ return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
34975
+ }
34976
+ duplicatePivot() {
34977
+ const newPivotId = this.env.model.uuidGenerator.uuidv4();
34978
+ const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
34979
+ pivotId: this.props.pivotId,
34980
+ newPivotId,
34981
+ });
34982
+ const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
34983
+ const type = result.isSuccessful ? "success" : "danger";
34984
+ this.env.notifyUser({
34985
+ text,
34986
+ sticky: false,
34987
+ type,
34988
+ });
34989
+ if (result.isSuccessful) {
34990
+ this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
34991
+ }
34992
+ }
34993
+ delete() {
34994
+ this.env.askConfirmation(_t("Are you sure you want to delete this pivot?"), () => {
34995
+ this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
34996
+ });
34997
+ }
34998
+ onNameChanged(name) {
34999
+ const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
35000
+ this.env.model.dispatch("UPDATE_PIVOT", {
35001
+ pivotId: this.props.pivotId,
35002
+ pivot: {
35003
+ ...pivot,
35004
+ name,
35005
+ },
35006
+ });
35007
+ }
35008
+ }
35009
+
34917
35010
  /**
34918
35011
  * Represent a pivot runtime definition. A pivot runtime definition is a pivot
34919
35012
  * definition that has been enriched to include the display name of its attributes
@@ -35218,7 +35311,7 @@ function dataEntriesToRows(dataEntries, index, rows, fields, values) {
35218
35311
  }
35219
35312
  const row = rows[index];
35220
35313
  const rowName = row.nameWithGranularity;
35221
- const groups = groupBy(dataEntries, row);
35314
+ const groups = groupPivotDataEntriesBy(dataEntries, row);
35222
35315
  const orderedKeys = orderDataEntriesKeys(groups, row);
35223
35316
  const pivotTableRows = [];
35224
35317
  const _fields = fields.concat(rowName);
@@ -35248,7 +35341,7 @@ function dataEntriesToColumnsTree(dataEntries, columns, index) {
35248
35341
  }
35249
35342
  const column = columns[index];
35250
35343
  const colName = columns[index].nameWithGranularity;
35251
- const groups = groupBy(dataEntries, column);
35344
+ const groups = groupPivotDataEntriesBy(dataEntries, column);
35252
35345
  const orderedKeys = orderDataEntriesKeys(groups, columns[index]);
35253
35346
  return orderedKeys.map((value) => {
35254
35347
  return {
@@ -35346,7 +35439,7 @@ function columnsTreeToColumns(mainTree, definition) {
35346
35439
  /**
35347
35440
  * Group the dataEntries based on the given dimension
35348
35441
  */
35349
- function groupBy(dataEntries, dimension) {
35442
+ function groupPivotDataEntriesBy(dataEntries, dimension) {
35350
35443
  return Object.groupBy(dataEntries, keySelector(dimension));
35351
35444
  }
35352
35445
  /**
@@ -35396,7 +35489,7 @@ function createDate(dimension, value, locale) {
35396
35489
  number = Math.floor(date.getMonth() / 3) + 1;
35397
35490
  break;
35398
35491
  case "month_number":
35399
- number = date.getMonth();
35492
+ number = date.getMonth() + 1;
35400
35493
  break;
35401
35494
  case "iso_week_number":
35402
35495
  number = date.getIsoWeek();
@@ -35408,7 +35501,7 @@ function createDate(dimension, value, locale) {
35408
35501
  number = Math.floor(toNumber(value, locale));
35409
35502
  break;
35410
35503
  }
35411
- MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = number;
35504
+ MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`] = toNormalizedPivotValue(dimension, number);
35412
35505
  }
35413
35506
  return MAP_VALUE_DIMENSION_DATE[granularity].values[`${value}`];
35414
35507
  }
@@ -35554,7 +35647,7 @@ class SpreadsheetPivot {
35554
35647
  return this._definition;
35555
35648
  }
35556
35649
  isValid() {
35557
- if (this.invalidRangeError || !this._definition) {
35650
+ if (this.invalidRangeError || !this.definition) {
35558
35651
  return false;
35559
35652
  }
35560
35653
  for (const measure of this.definition.measures) {
@@ -35611,25 +35704,19 @@ class SpreadsheetPivot {
35611
35704
  const dimension = this.getDimension(lastNode.field);
35612
35705
  const cells = this.filterDataEntriesFromDomain(this.dataEntries, domain);
35613
35706
  const finalCell = cells[0]?.[dimension.nameWithGranularity];
35707
+ if (dimension.type === "date") {
35708
+ const adapter = pivotTimeAdapter(dimension.granularity);
35709
+ return {
35710
+ value: adapter.toCellValue(toNormalizedPivotValue(dimension, lastNode.value)),
35711
+ format: adapter.getFormat(this.getters.getLocale()),
35712
+ };
35713
+ }
35614
35714
  if (!finalCell) {
35615
35715
  return { value: "" };
35616
35716
  }
35617
35717
  if (finalCell.value === null) {
35618
35718
  return { value: _t("(Undefined)") };
35619
35719
  }
35620
- if (dimension.type === "date") {
35621
- if (dimension.granularity === "day") {
35622
- return {
35623
- value: toNumber(finalCell.value, this.getters.getLocale()),
35624
- format: this.getters.getLocale().dateFormat,
35625
- };
35626
- }
35627
- if (dimension.granularity === "month_number") {
35628
- return {
35629
- value: MONTHS[toNumber(finalCell.value, this.getters.getLocale())].toString(),
35630
- };
35631
- }
35632
- }
35633
35720
  return {
35634
35721
  value: finalCell.value,
35635
35722
  format: finalCell.format,
@@ -35654,9 +35741,12 @@ class SpreadsheetPivot {
35654
35741
  format: operator.format(values[0]),
35655
35742
  };
35656
35743
  }
35657
- getPossibleFieldValues(groupBy) {
35658
- //TODO This method should be implemented for the autocomplete feature
35659
- throw new Error("Method not implemented.");
35744
+ getPossibleFieldValues(dimension) {
35745
+ const values = [];
35746
+ for (const value in groupPivotDataEntriesBy(this.dataEntries, dimension)) {
35747
+ values.push({ value, label: "" });
35748
+ }
35749
+ return values;
35660
35750
  }
35661
35751
  getTableStructure() {
35662
35752
  if (!this.isValid()) {
@@ -35676,7 +35766,8 @@ class SpreadsheetPivot {
35676
35766
  filterDataEntriesFromDomainNode(dataEntries, domain) {
35677
35767
  const { field, value } = domain;
35678
35768
  const dimension = this.getDimension(field);
35679
- return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` === value);
35769
+ return dataEntries.filter((entry) => `${entry[dimension.nameWithGranularity]?.value}` ===
35770
+ `${toNormalizedPivotValue(dimension, value)}`);
35680
35771
  }
35681
35772
  getDimension(nameWithGranularity) {
35682
35773
  return this.definition.getDimension(nameWithGranularity);
@@ -35812,15 +35903,8 @@ pivotRegistry.add("SPREADSHEET", {
35812
35903
 
35813
35904
  class PivotSidePanelStore extends SpreadsheetStore {
35814
35905
  pivotId;
35815
- mutators = [
35816
- "reset",
35817
- "deferUpdates",
35818
- "applyUpdate",
35819
- "discardPendingUpdate",
35820
- "renamePivot",
35821
- "update",
35822
- ];
35823
- updatesAreDeferred = true;
35906
+ mutators = ["reset", "deferUpdates", "applyUpdate", "discardPendingUpdate", "update"];
35907
+ updatesAreDeferred = false;
35824
35908
  draft = null;
35825
35909
  constructor(get, pivotId) {
35826
35910
  super(get);
@@ -35937,16 +36021,6 @@ class PivotSidePanelStore extends SpreadsheetStore {
35937
36021
  discardPendingUpdate() {
35938
36022
  this.draft = null;
35939
36023
  }
35940
- renamePivot(name) {
35941
- const pivot = this.getters.getPivotCoreDefinition(this.pivotId);
35942
- this.model.dispatch("UPDATE_PIVOT", {
35943
- pivotId: this.pivotId,
35944
- pivot: {
35945
- ...pivot,
35946
- name,
35947
- },
35948
- });
35949
- }
35950
36024
  update(definitionUpdate) {
35951
36025
  const coreDefinition = this.getters.getPivotCoreDefinition(this.pivotId);
35952
36026
  const definition = { ...coreDefinition, ...this.draft, ...definitionUpdate };
@@ -36029,9 +36103,9 @@ class PivotSpreadsheetSidePanel extends Component {
36029
36103
  PivotLayoutConfigurator,
36030
36104
  Section,
36031
36105
  SelectionInput,
36032
- EditableName,
36033
36106
  Checkbox,
36034
36107
  PivotDeferUpdate,
36108
+ PivotTitleSection,
36035
36109
  };
36036
36110
  store;
36037
36111
  state;
@@ -36060,12 +36134,6 @@ class PivotSpreadsheetSidePanel extends Component {
36060
36134
  get pivot() {
36061
36135
  return this.store.pivot;
36062
36136
  }
36063
- get name() {
36064
- return this.env.model.getters.getPivotName(this.props.pivotId);
36065
- }
36066
- get displayName() {
36067
- return this.env.model.getters.getPivotDisplayName(this.props.pivotId);
36068
- }
36069
36137
  get definition() {
36070
36138
  return this.store.definition;
36071
36139
  }
@@ -36089,35 +36157,9 @@ class PivotSpreadsheetSidePanel extends Component {
36089
36157
  this.store.applyUpdate();
36090
36158
  }
36091
36159
  }
36092
- duplicatePivot() {
36093
- const newPivotId = this.env.model.uuidGenerator.uuidv4();
36094
- const result = this.env.model.dispatch("DUPLICATE_PIVOT", {
36095
- pivotId: this.props.pivotId,
36096
- newPivotId,
36097
- });
36098
- const text = result.isSuccessful ? _t("Pivot duplicated.") : _t("Pivot duplication failed");
36099
- const type = result.isSuccessful ? "success" : "danger";
36100
- this.env.notifyUser({
36101
- text,
36102
- sticky: false,
36103
- type,
36104
- });
36105
- if (result.isSuccessful) {
36106
- this.env.openSidePanel("PivotSidePanel", { pivotId: newPivotId });
36107
- }
36108
- }
36109
- onNameChanged(name) {
36110
- this.store.renamePivot(name);
36111
- }
36112
36160
  onDimensionsUpdated(definition) {
36113
36161
  this.store.update(definition);
36114
36162
  }
36115
- back() {
36116
- this.env.openSidePanel("PivotSidePanel", {});
36117
- }
36118
- delete() {
36119
- this.env.model.dispatch("REMOVE_PIVOT", { pivotId: this.props.pivotId });
36120
- }
36121
36163
  }
36122
36164
 
36123
36165
  const pivotSidePanelRegistry = new Registry();
@@ -36125,44 +36167,17 @@ pivotSidePanelRegistry.add("SPREADSHEET", {
36125
36167
  editor: PivotSpreadsheetSidePanel,
36126
36168
  });
36127
36169
 
36128
- css /* scss */ `
36129
- .o_pivot_list_item {
36130
- cursor: pointer;
36131
- &:hover {
36132
- background-color: #f1f3f4;
36133
- }
36134
- }
36135
- `;
36136
- class PivotListItem extends Component {
36137
- static template = "o-spreadsheet-PivotListItem";
36138
- static props = { pivotId: String };
36139
- setup() {
36140
- const previewRef = useRef("pivotListItem");
36141
- useHighlightsOnHover(previewRef, this);
36142
- }
36143
- selectPivot() {
36144
- this.env.openSidePanel("PivotSidePanel", { pivotId: this.props.pivotId });
36145
- }
36146
- get highlights() {
36147
- return getPivotHighlights(this.env.model.getters, this.props.pivotId);
36148
- }
36149
- }
36150
-
36151
36170
  class PivotSidePanel extends Component {
36152
36171
  static template = "o-spreadsheet-PivotSidePanel";
36153
36172
  static props = {
36154
- pivotId: { type: String, optional: true },
36173
+ pivotId: String,
36155
36174
  onCloseSidePanel: Function,
36156
36175
  };
36157
36176
  static components = {
36158
36177
  PivotLayoutConfigurator,
36159
36178
  Section,
36160
- PivotListItem,
36161
36179
  };
36162
36180
  get sidePanelEditor() {
36163
- if (!this.props.pivotId) {
36164
- throw new Error("pivotId is required to call this function.");
36165
- }
36166
36181
  const pivot = this.env.model.getters.getPivotCoreDefinition(this.props.pivotId);
36167
36182
  if (!pivot) {
36168
36183
  throw new Error("pivotId does not correspond to a pivot.");
@@ -36179,6 +36194,7 @@ css /* scss */ `
36179
36194
  class RemoveDuplicatesPanel extends Component {
36180
36195
  static template = "o-spreadsheet-RemoveDuplicatesPanel";
36181
36196
  static components = { ValidationMessages, Section, Checkbox };
36197
+ static props = { onCloseSidePanel: Function };
36182
36198
  state = useState({
36183
36199
  hasHeader: false,
36184
36200
  columns: {},
@@ -37321,21 +37337,15 @@ sidePanelRegistry.add("TableStyleEditorPanel", {
37321
37337
  });
37322
37338
  sidePanelRegistry.add("PivotSidePanel", {
37323
37339
  title: (env, props) => {
37324
- if (props.pivotId) {
37325
- return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37326
- }
37327
- return _t("List of Pivots");
37340
+ return _t("Pivot #%s", env.model.getters.getPivotFormulaId(props.pivotId));
37328
37341
  },
37329
37342
  Body: PivotSidePanel,
37330
- computeState: (getters, initialProps) => {
37331
- if (!getters.getPivotIds().length) {
37332
- return { isOpen: false };
37333
- }
37334
- let { pivotId } = initialProps;
37335
- if (pivotId && !getters.isExistingPivot(pivotId)) {
37336
- pivotId = undefined;
37337
- }
37338
- return { isOpen: true, props: { pivotId }, key: `pivot_key_${pivotId}` };
37343
+ computeState: (getters, props) => {
37344
+ return {
37345
+ isOpen: getters.isExistingPivot(props.pivotId),
37346
+ props,
37347
+ key: `pivot_key_${props.pivotId}`,
37348
+ };
37339
37349
  },
37340
37350
  });
37341
37351
 
@@ -38603,7 +38613,7 @@ class FiguresContainer extends Component {
38603
38613
  });
38604
38614
  }
38605
38615
  getContainerRect(container) {
38606
- const { width: viewWidth, height: viewHeight } = this.env.model.getters.getMainViewportRect();
38616
+ const { width: viewWidth, height: viewHeight } = this.env.model.getters.getSheetViewDimension();
38607
38617
  const { x: viewportX, y: viewportY } = this.env.model.getters.getMainViewportCoordinates();
38608
38618
  const x = ["bottomRight", "topRight"].includes(container) ? viewportX : 0;
38609
38619
  const width = viewWidth - x;
@@ -41593,133 +41603,6 @@ class Grid extends Component {
41593
41603
  }
41594
41604
  }
41595
41605
 
41596
- const pivotTimeAdapterRegistry = new Registry();
41597
- function pivotTimeAdapter(granularity) {
41598
- return pivotTimeAdapterRegistry.get(granularity);
41599
- }
41600
- /**
41601
- * The Time Adapter: Managing Time Periods for Pivot Functions
41602
- *
41603
- * Overview:
41604
- * A time adapter is responsible for managing time periods associated with pivot functions.
41605
- * Each type of period (day, week, month, quarter, etc.) has its own dedicated adapter.
41606
- * The adapter's primary role is to normalize period values between spreadsheet functions,
41607
- * and the pivot.
41608
- * By normalizing the period value, it can be stored consistently in the pivot.
41609
- *
41610
- * Normalization Process:
41611
- * When working with functions in the spreadsheet, the time adapter normalizes
41612
- * the provided period to facilitate accurate lookup of values in the pivot.
41613
- * For instance, if the spreadsheet function represents a day period as a number generated
41614
- * by the DATE function (DATE(2023, 12, 25)), the time adapter will normalize it accordingly.
41615
- *
41616
- */
41617
- /**
41618
- * Normalized value: "12/25/2023"
41619
- *
41620
- * Note: Those two format are equivalent:
41621
- * - "MM/dd/yyyy" (luxon format)
41622
- * - "mm/dd/yyyy" (spreadsheet format)
41623
- **/
41624
- const dayAdapter = {
41625
- normalizeFunctionValue(value) {
41626
- const date = toNumber(value, DEFAULT_LOCALE);
41627
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/dd/yyyy" });
41628
- },
41629
- getFormat(locale) {
41630
- return (locale ?? DEFAULT_LOCALE).dateFormat;
41631
- },
41632
- formatValue(normalizedValue, locale) {
41633
- locale = locale ?? DEFAULT_LOCALE;
41634
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41635
- return formatValue(value, { locale, format: this.getFormat(locale) });
41636
- },
41637
- toCellValue(normalizedValue) {
41638
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41639
- },
41640
- };
41641
- /**
41642
- * Normalized value: "2/2023" for week 2 of 2023
41643
- */
41644
- const weekAdapter = {
41645
- normalizeFunctionValue(value) {
41646
- const [week, year] = value.split("/");
41647
- return `${Number(week)}/${Number(year)}`;
41648
- },
41649
- getFormat() {
41650
- return undefined;
41651
- },
41652
- formatValue(normalizedValue) {
41653
- const [week, year] = normalizedValue.split("/");
41654
- return _t("W%(week)s %(year)s", { week, year });
41655
- },
41656
- toCellValue(normalizedValue) {
41657
- return this.formatValue(normalizedValue);
41658
- },
41659
- };
41660
- /**
41661
- * normalized month value is a string formatted as "MM/yyyy" (luxon format)
41662
- * e.g. "01/2020" for January 2020
41663
- */
41664
- const monthAdapter = {
41665
- normalizeFunctionValue(value) {
41666
- const date = toNumber(value, DEFAULT_LOCALE);
41667
- return formatValue(date, { locale: DEFAULT_LOCALE, format: "mm/yyyy" });
41668
- },
41669
- getFormat() {
41670
- return "mmmm yyyy";
41671
- },
41672
- formatValue(normalizedValue, locale) {
41673
- locale = locale ?? DEFAULT_LOCALE;
41674
- const value = toNumber(normalizedValue, DEFAULT_LOCALE);
41675
- return formatValue(value, { locale, format: this.getFormat(locale) });
41676
- },
41677
- toCellValue(normalizedValue) {
41678
- return toNumber(normalizedValue, DEFAULT_LOCALE);
41679
- },
41680
- };
41681
- /**
41682
- * normalized quarter value is "quarter/year"
41683
- * e.g. "1/2020" for Q1 2020
41684
- */
41685
- const quarterAdapter = {
41686
- normalizeFunctionValue(value) {
41687
- const [quarter, year] = value.split("/");
41688
- return `${quarter}/${year}`;
41689
- },
41690
- getFormat() {
41691
- return undefined;
41692
- },
41693
- formatValue(normalizedValue) {
41694
- const [quarter, year] = normalizedValue.split("/");
41695
- return _t("Q%(quarter)s %(year)s", { quarter, year });
41696
- },
41697
- toCellValue(normalizedValue) {
41698
- return this.formatValue(normalizedValue);
41699
- },
41700
- };
41701
- const yearAdapter = {
41702
- normalizeFunctionValue(value) {
41703
- return toNumber(value, DEFAULT_LOCALE);
41704
- },
41705
- getFormat() {
41706
- return "0";
41707
- },
41708
- formatValue(normalizedValue, locale) {
41709
- locale = locale ?? DEFAULT_LOCALE;
41710
- return formatValue(normalizedValue, { locale, format: "0" });
41711
- },
41712
- toCellValue(normalizedValue) {
41713
- return normalizedValue;
41714
- },
41715
- };
41716
- pivotTimeAdapterRegistry
41717
- .add("day", dayAdapter)
41718
- .add("week", weekAdapter)
41719
- .add("month", monthAdapter)
41720
- .add("quarter", quarterAdapter)
41721
- .add("year", yearAdapter);
41722
-
41723
41606
  /**
41724
41607
  * Represent a raw XML string
41725
41608
  */
@@ -46918,9 +46801,14 @@ class CellPlugin extends CorePlugin {
46918
46801
  }
46919
46802
  createLiteralCell(id, content, format, style) {
46920
46803
  const locale = this.getters.getLocale();
46921
- format = format || detectDateFormat(content, locale) || detectNumberFormat(content);
46804
+ const parsedValue = parseLiteral(content, locale);
46805
+ format =
46806
+ format ||
46807
+ (typeof parsedValue === "number"
46808
+ ? detectDateFormat(content, locale) || detectNumberFormat(content)
46809
+ : undefined);
46922
46810
  if (format !== PLAIN_TEXT_FORMAT && !isEvaluationError(content)) {
46923
- content = toString(parseLiteral(content, locale));
46811
+ content = toString(parsedValue);
46924
46812
  }
46925
46813
  return {
46926
46814
  id,
@@ -46928,6 +46816,7 @@ class CellPlugin extends CorePlugin {
46928
46816
  style,
46929
46817
  format,
46930
46818
  isFormula: false,
46819
+ parsedValue,
46931
46820
  };
46932
46821
  }
46933
46822
  createFormulaCell(id, content, format, style, sheetId) {
@@ -51225,22 +51114,6 @@ class PivotCorePlugin extends CorePlugin {
51225
51114
  this.addPivotFormula(cellPosition, formulaId, pivotCell);
51226
51115
  }
51227
51116
  }
51228
- const pivotZone = {
51229
- top: position.row,
51230
- bottom: position.row + pivotCells[0].length - 1,
51231
- left: position.col,
51232
- right: position.col + pivotCells.length - 1,
51233
- };
51234
- const numberOfHeaders = table.columns.length - 1;
51235
- const cmdContent = {
51236
- sheetId: position.sheetId,
51237
- ranges: [this.getters.getRangeDataFromZone(position.sheetId, pivotZone)],
51238
- config: { ...PIVOT_TABLE_CONFIG, numberOfHeaders },
51239
- tableType: "static",
51240
- };
51241
- if (this.canDispatch("CREATE_TABLE", cmdContent).isSuccessful) {
51242
- this.dispatch("CREATE_TABLE", cmdContent);
51243
- }
51244
51117
  }
51245
51118
  resizeSheet(sheetId, { col, row }, table) {
51246
51119
  const colLimit = table.getNumberOfDataColumns() + 1; // +1 for the Top-Left
@@ -51670,6 +51543,9 @@ class PositionMap {
51670
51543
  get({ sheetId, col, row }) {
51671
51544
  return this.map[sheetId]?.[col]?.[row];
51672
51545
  }
51546
+ getSheet(sheetId) {
51547
+ return this.map[sheetId];
51548
+ }
51673
51549
  has({ sheetId, col, row }) {
51674
51550
  return this.map[sheetId]?.[col]?.[row] !== undefined;
51675
51551
  }
@@ -51688,6 +51564,19 @@ class PositionMap {
51688
51564
  }
51689
51565
  return keys;
51690
51566
  }
51567
+ keysForSheet(sheetId) {
51568
+ const map = this.map[sheetId];
51569
+ if (!map) {
51570
+ return [];
51571
+ }
51572
+ const keys = [];
51573
+ for (const col in map) {
51574
+ for (const row in map[col]) {
51575
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
51576
+ }
51577
+ }
51578
+ return keys;
51579
+ }
51691
51580
  }
51692
51581
 
51693
51582
  function quickselect(arr, k, left, right, compare) {
@@ -52766,6 +52655,9 @@ class Evaluator {
52766
52655
  getEvaluatedPositions() {
52767
52656
  return this.evaluatedCells.keys();
52768
52657
  }
52658
+ getEvaluatedPositionsInSheet(sheetId) {
52659
+ return this.evaluatedCells.keysForSheet(sheetId);
52660
+ }
52769
52661
  getArrayFormulaSpreadingOn(position) {
52770
52662
  if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
52771
52663
  return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
@@ -52774,6 +52666,9 @@ class Evaluator {
52774
52666
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
52775
52667
  }
52776
52668
  updateDependencies(position) {
52669
+ // removing dependencies is slow because it requires
52670
+ // to traverse the entire r-tree.
52671
+ // The data structure is optimized for searches the other way around
52777
52672
  this.formulaDependencies().removeAllDependencies(position);
52778
52673
  const dependencies = this.getDirectDependencies(position);
52779
52674
  this.formulaDependencies().addDependencies(position, dependencies);
@@ -52939,7 +52834,7 @@ class Evaluator {
52939
52834
  this.cellsBeingComputed.add(cellId);
52940
52835
  return cell.isFormula
52941
52836
  ? this.computeFormulaCell(position.sheetId, cell)
52942
- : evaluateLiteral(cell.content, localeFormat);
52837
+ : evaluateLiteral(cell, localeFormat);
52943
52838
  }
52944
52839
  catch (e) {
52945
52840
  e.value = e?.value || CellErrorType.GenericError;
@@ -53209,6 +53104,7 @@ class EvaluationPlugin extends UIPlugin {
53209
53104
  "getEvaluatedCell",
53210
53105
  "getEvaluatedCells",
53211
53106
  "getEvaluatedCellsInZone",
53107
+ "getEvaluatedCellsPositions",
53212
53108
  "getSpreadZone",
53213
53109
  "getArrayFormulaSpreadingOn",
53214
53110
  "isEmpty",
@@ -53300,13 +53196,12 @@ class EvaluationPlugin extends UIPlugin {
53300
53196
  return this.evaluator.getEvaluatedCell(position);
53301
53197
  }
53302
53198
  getEvaluatedCells(sheetId) {
53303
- const rawCells = this.getters.getCells(sheetId) || {};
53304
- const record = {};
53305
- for (let cellId of Object.keys(rawCells)) {
53306
- const position = this.getters.getCellPosition(cellId);
53307
- record[cellId] = this.getEvaluatedCell(position);
53308
- }
53309
- return record;
53199
+ return this.evaluator
53200
+ .getEvaluatedPositionsInSheet(sheetId)
53201
+ .map((position) => this.getEvaluatedCell(position));
53202
+ }
53203
+ getEvaluatedCellsPositions(sheetId) {
53204
+ return this.evaluator.getEvaluatedPositionsInSheet(sheetId);
53310
53205
  }
53311
53206
  getEvaluatedCellsInZone(sheetId, zone) {
53312
53207
  return positions(zone).map(({ col, row }) => this.getters.getEvaluatedCell({ sheetId, col, row }));
@@ -55974,7 +55869,10 @@ class Session extends EventBus {
55974
55869
  /**
55975
55870
  * Notify the server that the user client left the collaborative session
55976
55871
  */
55977
- leave() {
55872
+ leave(data) {
55873
+ if (Object.keys(this.clients).length === 1 && this.processedRevisions.size) {
55874
+ this.snapshot(data);
55875
+ }
55978
55876
  delete this.clients[this.clientId];
55979
55877
  this.transportService.leave(this.clientId);
55980
55878
  this.transportService.sendMessage({
@@ -55987,6 +55885,9 @@ class Session extends EventBus {
55987
55885
  * Send a snapshot of the spreadsheet to the collaboration server
55988
55886
  */
55989
55887
  snapshot(data) {
55888
+ if (this.pendingMessages.length !== 0) {
55889
+ return;
55890
+ }
55990
55891
  const snapshotId = this.uuidGenerator.uuidv4();
55991
55892
  this.transportService.sendMessage({
55992
55893
  type: "SNAPSHOT",
@@ -56388,7 +56289,7 @@ class DataCleanupPlugin extends UIPlugin {
56388
56289
  bottom: rowIndex,
56389
56290
  }));
56390
56291
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
56391
- const data = handler.copy(getClipboardDataPositions(rowsToKeep));
56292
+ const data = handler.copy(getClipboardDataPositions(sheetId, rowsToKeep));
56392
56293
  if (!data) {
56393
56294
  return;
56394
56295
  }
@@ -56401,7 +56302,7 @@ class DataCleanupPlugin extends UIPlugin {
56401
56302
  right: zone.left,
56402
56303
  bottom: zone.top,
56403
56304
  };
56404
- handler.paste({ zones: [zonePasted] }, data, { isCutOperation: false });
56305
+ handler.paste({ zones: [zonePasted], sheetId }, data, { isCutOperation: false });
56405
56306
  const remainingZone = {
56406
56307
  left: zone.left,
56407
56308
  top: zone.top - (hasHeader ? 1 : 0),
@@ -58275,12 +58176,14 @@ class ClipboardPlugin extends UIPlugin {
58275
58176
  }
58276
58177
  let zone = undefined;
58277
58178
  let selectedZones = [];
58179
+ const sheetId = this.getters.getActiveSheetId();
58278
58180
  let target = {
58181
+ sheetId,
58279
58182
  zones,
58280
58183
  };
58281
58184
  const handlers = this.selectClipboardHandlers(copiedData);
58282
58185
  for (const handler of handlers) {
58283
- const currentTarget = handler.getPasteTarget(zones, copiedData, options);
58186
+ const currentTarget = handler.getPasteTarget(sheetId, zones, copiedData, options);
58284
58187
  if (currentTarget.figureId) {
58285
58188
  target.figureId = currentTarget.figureId;
58286
58189
  }
@@ -58449,11 +58352,12 @@ class ClipboardPlugin extends UIPlugin {
58449
58352
  return { cut: [cut], paste: [paste] };
58450
58353
  }
58451
58354
  getClipboardData(zones) {
58355
+ const sheetId = this.getters.getActiveSheetId();
58452
58356
  const selectedFigureId = this.getters.getSelectedFigureId();
58453
58357
  if (selectedFigureId) {
58454
- return { figureId: selectedFigureId };
58358
+ return { figureId: selectedFigureId, sheetId };
58455
58359
  }
58456
- return getClipboardDataPositions(zones);
58360
+ return getClipboardDataPositions(sheetId, zones);
58457
58361
  }
58458
58362
  // ---------------------------------------------------------------------------
58459
58363
  // Grid rendering
@@ -59119,8 +59023,9 @@ class GridSelectionPlugin extends UIPlugin {
59119
59023
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
59120
59024
  },
59121
59025
  ];
59026
+ const sheetId = this.getActiveSheetId();
59122
59027
  const handler = new CellClipboardHandler(this.getters, this.dispatch);
59123
- const data = handler.copy(getClipboardDataPositions(target));
59028
+ const data = handler.copy(getClipboardDataPositions(sheetId, target));
59124
59029
  if (!data) {
59125
59030
  return;
59126
59031
  }
@@ -59133,7 +59038,7 @@ class GridSelectionPlugin extends UIPlugin {
59133
59038
  bottom: !isCol ? base + thickness - 1 : this.getters.getNumberRows(cmd.sheetId) - 1,
59134
59039
  },
59135
59040
  ];
59136
- handler.paste({ zones: pasteTarget }, data, { isCutOperation: true });
59041
+ handler.paste({ zones: pasteTarget, sheetId }, data, { isCutOperation: true });
59137
59042
  const toRemove = isBasedBefore ? cmd.elements.map((el) => el + thickness) : cmd.elements;
59138
59043
  let currentIndex = cmd.base;
59139
59044
  for (const element of toRemove) {
@@ -66497,7 +66402,7 @@ class Model extends EventBus {
66497
66402
  this.session.join(this.config.client);
66498
66403
  }
66499
66404
  leaveSession() {
66500
- this.session.leave();
66405
+ this.session.leave(this.exportData());
66501
66406
  }
66502
66407
  setupUiPlugin(Plugin) {
66503
66408
  const plugin = new Plugin(this.uiPluginConfig);
@@ -66904,7 +66809,8 @@ const registries = {
66904
66809
  pivotRegistry,
66905
66810
  pivotTimeAdapterRegistry,
66906
66811
  pivotSidePanelRegistry,
66907
- supportedPivotExplodedFormulaRegistry,
66812
+ pivotNormalizationValueRegistry,
66813
+ supportedPivotPositionalFormulaRegistry,
66908
66814
  };
66909
66815
  const helpers = {
66910
66816
  arg,
@@ -66913,6 +66819,7 @@ const helpers = {
66913
66819
  toJsDate,
66914
66820
  toNumber,
66915
66821
  toString,
66822
+ toNormalizedPivotValue,
66916
66823
  toXC,
66917
66824
  toZone,
66918
66825
  toUnboundedZone,
@@ -67008,6 +66915,8 @@ const components = {
67008
66915
  PivotLayoutConfigurator,
67009
66916
  EditableName,
67010
66917
  PivotDeferUpdate,
66918
+ PivotTitleSection,
66919
+ CogWheelMenu,
67011
66920
  };
67012
66921
  const hooks = {
67013
66922
  useDragAndDropListItems,
@@ -67048,6 +66957,6 @@ const constants = {
67048
66957
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, PivotRuntimeDefinition, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, SpreadsheetPivotTable, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
67049
66958
 
67050
66959
 
67051
- __info__.version = "17.4.0-alpha.3";
67052
- __info__.date = "2024-06-10T09:38:53.982Z";
67053
- __info__.hash = "a45ed6a";
66960
+ __info__.version = "17.4.0-alpha.5";
66961
+ __info__.date = "2024-06-14T10:01:40.605Z";
66962
+ __info__.hash = "9ceed96";