@odoo/o-spreadsheet 17.0.71 → 17.0.73

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.
@@ -2,9 +2,9 @@
2
2
  /**
3
3
  * This file is generated by o-spreadsheet build tools. Do not edit it.
4
4
  * @see https://github.com/odoo/o-spreadsheet
5
- * @version 17.0.71
6
- * @date 2025-08-21T06:37:34.192Z
7
- * @hash 1592964
5
+ * @version 17.0.73
6
+ * @date 2025-09-11T08:40:46.367Z
7
+ * @hash a11c622
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -11421,8 +11421,11 @@
11421
11421
  // (a) Swap 2 rows. This multiply the determinant by -1.
11422
11422
  // (b) Multiply a row by a scalar. This multiply the determinant by that scalar.
11423
11423
  // (c) Add to a row a multiple of another row. This does not change the determinant.
11424
+ if (M.length < 1 || M[0].length < 1) {
11425
+ throw new Error("invertMatrix: an empty matrix cannot be inverted.");
11426
+ }
11424
11427
  if (M.length !== M[0].length) {
11425
- throw new Error(`Function [[FUNCTION_NAME]] invert matrix error, only square matrices are invertible`);
11428
+ throw new Error("invertMatrix: only square matrices are invertible");
11426
11429
  }
11427
11430
  let determinant = 1;
11428
11431
  const dim = M.length;
@@ -11491,8 +11494,11 @@
11491
11494
  * Note: we use indexing [col][row] instead of the standard mathematical notation [row][col]
11492
11495
  */
11493
11496
  function multiplyMatrices(matrix1, matrix2) {
11497
+ if (matrix1.length < 1 || matrix2.length < 1) {
11498
+ throw new Error("multiplyMatrices: empty matrices cannot be multiplied.");
11499
+ }
11494
11500
  if (matrix1.length !== matrix2[0].length) {
11495
- throw new Error(_t("Cannot multiply matrices : incompatible matrices size."));
11501
+ throw new Error("multiplyMatrices: incompatible matrices size.");
11496
11502
  }
11497
11503
  const rowsM1 = matrix1[0].length;
11498
11504
  const colsM2 = matrix2.length;
@@ -11760,6 +11766,7 @@
11760
11766
  compute: function (matrix1, matrix2) {
11761
11767
  const _matrix1 = toMatrix(matrix1);
11762
11768
  const _matrix2 = toMatrix(matrix2);
11769
+ assert(() => _matrix1.length > 0 && _matrix2.length > 0, _t("The first and second arguments of [[FUNCTION_NAME]] must be non-empty matrices."));
11763
11770
  assert(() => _matrix1.length === _matrix2[0].length, _t("In [[FUNCTION_NAME]], the number of columns of the first matrix (%s) must be equal to the \
11764
11771
  number of rows of the second matrix (%s).", _matrix1.length.toString(), _matrix2[0].length.toString()));
11765
11772
  if (!isNumberMatrix(_matrix1) || !isNumberMatrix(_matrix2)) {
@@ -13249,6 +13256,16 @@
13249
13256
  const dims = args[0].length;
13250
13257
  args.forEach((arg, i) => assert(() => arg.length === dims, _t("[[FUNCTION_NAME]] has mismatched dimensions for argument %s (%s vs %s).", i.toString(), dims.toString(), arg.length.toString())));
13251
13258
  }
13259
+ function assertNonEmptyMatrix(matrix, argName) {
13260
+ assert(() => matrix.length > 0 && matrix[0].length > 0, _t("[[FUNCTION_NAME]] expects the provided values of %(argName)s to be a non-empty matrix.", {
13261
+ argName,
13262
+ }));
13263
+ }
13264
+ function assertNonEmpty(...data) {
13265
+ if (data.length === 0 || data.some((arg) => arg.length === 0)) {
13266
+ throw new NotAvailableError(_t("[[FUNCTION_NAME]] has no valid input data."));
13267
+ }
13268
+ }
13252
13269
 
13253
13270
  function filterAndFlatData(dataY, dataX) {
13254
13271
  const _flatDataY = [];
@@ -13779,6 +13796,7 @@
13779
13796
  returns: ["NUMBER"],
13780
13797
  compute: function (x, dataY, dataX) {
13781
13798
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13799
+ assertNonEmpty(flatDataX, flatDataY);
13782
13800
  return predictLinearValues([flatDataY], [flatDataX], matrixMap(toMatrix(x), (value) => toNumber(value, this.locale)), true);
13783
13801
  },
13784
13802
  isExported: true,
@@ -13796,6 +13814,7 @@
13796
13814
  ],
13797
13815
  returns: ["NUMBER"],
13798
13816
  compute: function (knownDataY, knownDataX = [], newDataX = [], b = true) {
13817
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
13799
13818
  return expM(predictLinearValues(logM(tryCastAsNumberMatrix(knownDataY, "the first argument (known_data_y)")), tryCastAsNumberMatrix(knownDataX, "the second argument (known_data_x)"), tryCastAsNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b)));
13800
13819
  },
13801
13820
  };
@@ -13811,6 +13830,7 @@
13811
13830
  returns: ["NUMBER"],
13812
13831
  compute: function (dataY, dataX) {
13813
13832
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
13833
+ assertNonEmpty(flatDataX, flatDataY);
13814
13834
  const [[], [intercept]] = fullLinearRegression([flatDataX], [flatDataY]);
13815
13835
  return intercept;
13816
13836
  },
@@ -13862,6 +13882,7 @@
13862
13882
  ],
13863
13883
  returns: ["NUMBER"],
13864
13884
  compute: function (dataY, dataX = [], calculateB = true, verbose = false) {
13885
+ assertNonEmptyMatrix(dataY, "data_y");
13865
13886
  return fullLinearRegression(tryCastAsNumberMatrix(dataX, "the first argument (data_y)"), tryCastAsNumberMatrix(dataY, "the second argument (data_x)"), toBoolean(calculateB), toBoolean(verbose));
13866
13887
  },
13867
13888
  isExported: true,
@@ -13879,6 +13900,7 @@
13879
13900
  ],
13880
13901
  returns: ["NUMBER"],
13881
13902
  compute: function (dataY, dataX = [], calculateB = true, verbose = false) {
13903
+ assertNonEmptyMatrix(dataY, "data_y");
13882
13904
  const coeffs = fullLinearRegression(tryCastAsNumberMatrix(dataX, "the second argument (data_x)"), logM(tryCastAsNumberMatrix(dataY, "the first argument (data_y)")), toBoolean(calculateB), toBoolean(verbose));
13883
13905
  for (let i = 0; i < coeffs.length; i++) {
13884
13906
  coeffs[i][0] = Math.exp(coeffs[i][0]);
@@ -13901,9 +13923,7 @@
13901
13923
  const flatX = dataX.flat();
13902
13924
  const flatY = dataY.flat();
13903
13925
  assertSameNumberOfElements(flatX, flatY);
13904
- if (flatX.length === 0) {
13905
- throw new Error(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
13906
- }
13926
+ assertNonEmpty(flatX, flatY);
13907
13927
  const n = flatX.length;
13908
13928
  let trueN = 0, trueP = 0, falseP = 0, falseN = 0;
13909
13929
  for (let i = 0; i < n; ++i) {
@@ -14097,12 +14117,7 @@
14097
14117
  returns: ["NUMBER"],
14098
14118
  compute: function (dataY, dataX) {
14099
14119
  const { flatDataX, flatDataY } = filterAndFlatData(dataX, dataY);
14100
- if (flatDataX.length === 0) {
14101
- throw new Error(_t("[[FUNCTION_NAME]] expects non-empty ranges for both parameters."));
14102
- }
14103
- if (flatDataX.length < 2) {
14104
- throw new Error(_t("[[FUNCTION_NAME]] needs at least two values for both parameters"));
14105
- }
14120
+ assertNonEmpty(flatDataX, flatDataY);
14106
14121
  const n = flatDataX.length;
14107
14122
  let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0, sumYY = 0;
14108
14123
  for (let i = 0; i < n; i++) {
@@ -14188,6 +14203,7 @@
14188
14203
  returns: ["RANGE<NUMBER>"],
14189
14204
  compute: function (dataY, dataX, order, intercept = true) {
14190
14205
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14206
+ assertNonEmpty(flatDataX, flatDataY);
14191
14207
  return polynomialRegression(flatDataY, flatDataX, toNumber(order, this.locale), toBoolean(intercept));
14192
14208
  },
14193
14209
  isExported: false,
@@ -14208,6 +14224,7 @@
14208
14224
  compute: function (x, dataY, dataX, order, intercept = true) {
14209
14225
  const _order = toNumber(order, this.locale);
14210
14226
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14227
+ assertNonEmpty(flatDataX, flatDataY);
14211
14228
  const coeffs = polynomialRegression(flatDataY, flatDataX, _order, toBoolean(intercept)).flat();
14212
14229
  return matrixMap(toMatrix(x), (xij) => evaluatePolynomial(coeffs, toNumber(xij, this.locale), _order));
14213
14230
  },
@@ -14333,6 +14350,7 @@
14333
14350
  returns: ["NUMBER"],
14334
14351
  compute: function (dataY, dataX) {
14335
14352
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14353
+ assertNonEmpty(flatDataX, flatDataY);
14336
14354
  const [[slope]] = fullLinearRegression([flatDataX], [flatDataY]);
14337
14355
  return slope;
14338
14356
  },
@@ -14383,6 +14401,7 @@
14383
14401
  returns: ["NUMBER"],
14384
14402
  compute: function (dataX, dataY) {
14385
14403
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14404
+ assertNonEmpty(flatDataX, flatDataY);
14386
14405
  const n = flatDataX.length;
14387
14406
  const order = flatDataX.map((e, i) => [e, flatDataY[i]]);
14388
14407
  order.sort((a, b) => a[0] - b[0]);
@@ -14500,6 +14519,7 @@
14500
14519
  returns: ["NUMBER"],
14501
14520
  compute: function (dataY, dataX) {
14502
14521
  const { flatDataX, flatDataY } = filterAndFlatData(dataY, dataX);
14522
+ assertNonEmpty(flatDataX, flatDataY);
14503
14523
  const data = fullLinearRegression([flatDataX], [flatDataY], true, true);
14504
14524
  return data[1][2];
14505
14525
  },
@@ -14518,6 +14538,7 @@
14518
14538
  ],
14519
14539
  returns: ["NUMBER"],
14520
14540
  compute: function (knownDataY, knownDataX = [], newDataX = [], b = true) {
14541
+ assertNonEmptyMatrix(knownDataY, "known_data_y");
14521
14542
  return predictLinearValues(tryCastAsNumberMatrix(knownDataY, "the first argument (known_data_y)"), tryCastAsNumberMatrix(knownDataX, "the second argument (known_data_x)"), tryCastAsNumberMatrix(newDataX, "the third argument (new_data_y)"), toBoolean(b));
14522
14543
  },
14523
14544
  };
@@ -31644,7 +31665,7 @@
31644
31665
  ];
31645
31666
  const SUPPORTED_VERTICAL_ALIGNMENTS = ["top", "center", "bottom"];
31646
31667
  const SUPPORTED_FONTS = ["Arial"];
31647
- const SUPPORTED_FILL_PATTERNS = ["solid"];
31668
+ const SUPPORTED_FILL_PATTERNS = ["solid", "none"];
31648
31669
  const SUPPORTED_CF_TYPES = [
31649
31670
  "expression",
31650
31671
  "cellIs",
@@ -31828,7 +31849,7 @@
31828
31849
  };
31829
31850
  /** Mapping between Excel format indexes (see XLSX_FORMAT_MAP) and some supported formats */
31830
31851
  const XLSX_FORMATS_CONVERSION_MAP = {
31831
- 0: "",
31852
+ 0: "General",
31832
31853
  1: "0",
31833
31854
  2: "0.00",
31834
31855
  3: "#,#00",
@@ -32127,11 +32148,11 @@
32127
32148
  * Excel format are defined in openXML §18.8.31
32128
32149
  */
32129
32150
  function convertXlsxFormat(numFmtId, formats, warningManager) {
32130
- if (numFmtId === 0) {
32131
- return undefined;
32132
- }
32133
32151
  // Format is either defined in the imported data, or the formatId is defined in openXML §18.8.30
32134
32152
  let format = XLSX_FORMATS_CONVERSION_MAP[numFmtId] || formats.find((f) => f.id === numFmtId)?.format;
32153
+ if (format === "General") {
32154
+ return undefined;
32155
+ }
32135
32156
  if (format) {
32136
32157
  try {
32137
32158
  let convertedFormat = format.replace(/(.*?);.*/, "$1"); // only take first part of multi-part format
@@ -34433,10 +34454,11 @@
34433
34454
  });
34434
34455
  }
34435
34456
  extractRows(worksheet) {
34457
+ const spilledCells = new Set();
34436
34458
  return this.mapOnElements({ parent: worksheet, query: "sheetData row" }, (rowElement) => {
34437
34459
  return {
34438
34460
  index: this.extractAttr(rowElement, "r", { required: true })?.asNum(),
34439
- cells: this.extractCells(rowElement),
34461
+ cells: this.extractCells(rowElement, spilledCells),
34440
34462
  height: this.extractAttr(rowElement, "ht")?.asNum(),
34441
34463
  customHeight: this.extractAttr(rowElement, "customHeight")?.asBool(),
34442
34464
  hidden: this.extractAttr(rowElement, "hidden")?.asBool(),
@@ -34444,14 +34466,26 @@
34444
34466
  };
34445
34467
  });
34446
34468
  }
34447
- extractCells(row) {
34469
+ extractCells(row, spilledCells) {
34448
34470
  return this.mapOnElements({ parent: row, query: "c" }, (cellElement) => {
34471
+ const xc = this.extractAttr(cellElement, "r", { required: true })?.asString();
34472
+ const formula = this.extractCellFormula(cellElement);
34473
+ if (formula?.ref && formula.sharedIndex === undefined) {
34474
+ const zone = toZone(formula.ref);
34475
+ for (const { col, row } of positions(zone)) {
34476
+ const followerXc = toXC(col, row);
34477
+ if (followerXc !== xc) {
34478
+ spilledCells.add(followerXc);
34479
+ }
34480
+ }
34481
+ }
34482
+ const isSpilled = spilledCells.has(xc);
34449
34483
  return {
34450
- xc: this.extractAttr(cellElement, "r", { required: true })?.asString(),
34484
+ xc,
34451
34485
  styleIndex: this.extractAttr(cellElement, "s")?.asNum(),
34452
34486
  type: CELL_TYPE_CONVERSION_MAP[this.extractAttr(cellElement, "t", { default: "n" })?.asString()],
34453
- value: this.extractChildTextContent(cellElement, "v"),
34454
- formula: this.extractCellFormula(cellElement),
34487
+ value: isSpilled ? undefined : this.extractChildTextContent(cellElement, "v") ?? undefined,
34488
+ formula: isSpilled ? undefined : formula,
34455
34489
  };
34456
34490
  });
34457
34491
  }
@@ -34459,11 +34493,14 @@
34459
34493
  const formulaElement = this.querySelector(cellElement, "f");
34460
34494
  if (!formulaElement)
34461
34495
  return undefined;
34462
- return {
34463
- content: this.extractTextContent(formulaElement),
34464
- sharedIndex: this.extractAttr(formulaElement, "si")?.asNum(),
34465
- ref: this.extractAttr(formulaElement, "ref")?.asString(),
34466
- };
34496
+ const content = this.extractTextContent(formulaElement);
34497
+ const sharedIndex = this.extractAttr(formulaElement, "si")?.asNum();
34498
+ const ref = this.extractAttr(formulaElement, "ref")?.asString();
34499
+ // This is the case of spilled cells of array formulas where <f> is empty
34500
+ if ((content === undefined || content.trim() === "") && sharedIndex === undefined) {
34501
+ return undefined;
34502
+ }
34503
+ return { content, sharedIndex, ref };
34467
34504
  }
34468
34505
  extractHyperLinks(worksheet) {
34469
34506
  return this.mapOnElements({ parent: worksheet, query: "hyperlink" }, (linkElement) => {
@@ -45497,7 +45534,7 @@
45497
45534
  queuedBordersToAdd = {};
45498
45535
  queuedCFChanges = {};
45499
45536
  queuedDVChanges = {};
45500
- constructor(zones, operation, getters, dispatch, selection) {
45537
+ constructor(zones, operation, getters, dispatch, selection, mode = "copyPaste") {
45501
45538
  super(operation, getters, dispatch, selection);
45502
45539
  if (!zones.length) {
45503
45540
  this.cells = [[]];
@@ -45527,7 +45564,7 @@
45527
45564
  const spreader = getters.getArrayFormulaSpreadingOn(position);
45528
45565
  let cell = getters.getCell(position);
45529
45566
  const evaluatedCell = getters.getEvaluatedCell(position);
45530
- if (spreader) {
45567
+ if (mode !== "shiftCells" && spreader) {
45531
45568
  const isSpreaderCopied = rowsIndex.includes(spreader.row) && columnsIndex.includes(spreader.col);
45532
45569
  const content = isSpreaderCopied
45533
45570
  ? ""
@@ -49088,12 +49125,12 @@
49088
49125
  }
49089
49126
  case "INSERT_CELL": {
49090
49127
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49091
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49128
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49092
49129
  return state.isPasteAllowed(paste);
49093
49130
  }
49094
49131
  case "DELETE_CELL": {
49095
49132
  const { cut, paste } = this.getDeleteCellsTargets(cmd.zone, cmd.shiftDimension);
49096
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49133
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49097
49134
  return state.isPasteAllowed(paste);
49098
49135
  }
49099
49136
  case "ACTIVATE_PAINT_FORMAT": {
@@ -49174,13 +49211,13 @@
49174
49211
  });
49175
49212
  break;
49176
49213
  }
49177
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49214
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49178
49215
  state.paste(paste);
49179
49216
  break;
49180
49217
  }
49181
49218
  case "INSERT_CELL": {
49182
49219
  const { cut, paste } = this.getInsertCellsTargets(cmd.zone, cmd.shiftDimension);
49183
- const state = this.getClipboardStateForCopyCells(cut, "CUT");
49220
+ const state = this.getClipboardStateForCopyCells(cut, "CUT", "shiftCells");
49184
49221
  state.paste(paste);
49185
49222
  break;
49186
49223
  }
@@ -49330,8 +49367,8 @@
49330
49367
  }
49331
49368
  return { cut: [cut], paste: [paste] };
49332
49369
  }
49333
- getClipboardStateForCopyCells(zones, operation) {
49334
- return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection);
49370
+ getClipboardStateForCopyCells(zones, operation, mode = "copyPaste") {
49371
+ return new ClipboardCellsState(zones, operation, this.getters, this.dispatch, this.selection, mode);
49335
49372
  }
49336
49373
  /**
49337
49374
  * Get the clipboard state from the given zones.
@@ -50901,7 +50938,7 @@
50901
50938
  bottom: !isCol ? end + deltaRow : this.getters.getNumberRows(cmd.sheetId) - 1,
50902
50939
  },
50903
50940
  ];
50904
- const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection);
50941
+ const state = new ClipboardCellsState(target, "CUT", this.getters, this.dispatch, this.selection, "shiftCells");
50905
50942
  const base = isBasedBefore ? cmd.base : cmd.base + 1;
50906
50943
  const pasteTarget = [
50907
50944
  {
@@ -58453,9 +58490,9 @@
58453
58490
  exports.tokenize = tokenize;
58454
58491
 
58455
58492
 
58456
- __info__.version = "17.0.71";
58457
- __info__.date = "2025-08-21T06:37:34.192Z";
58458
- __info__.hash = "1592964";
58493
+ __info__.version = "17.0.73";
58494
+ __info__.date = "2025-09-11T08:40:46.367Z";
58495
+ __info__.hash = "a11c622";
58459
58496
 
58460
58497
 
58461
58498
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);