@odoo/o-spreadsheet 18.0.28 → 18.0.29

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 18.0.28
6
- * @date 2025-05-13T17:53:12.402Z
7
- * @hash b3088aa
5
+ * @version 18.0.29
6
+ * @date 2025-05-20T05:54:57.329Z
7
+ * @hash 8213c0e
8
8
  */
9
9
 
10
10
  import { useEnv, useSubEnv, onWillUnmount, useComponent, status, Component, useRef, onMounted, useEffect, useState, onPatched, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv, markRaw, toRaw } from '@odoo/owl';
@@ -1452,18 +1452,53 @@ function lettersToNumber(letters) {
1452
1452
  let result = 0;
1453
1453
  const l = letters.length;
1454
1454
  for (let i = 0; i < l; i++) {
1455
- const charCode = letters.charCodeAt(i);
1456
- const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1455
+ const colIndex = charToNumber(letters[i]);
1457
1456
  result = result * 26 + colIndex;
1458
1457
  }
1459
1458
  return result - 1;
1460
1459
  }
1460
+ function charToNumber(char) {
1461
+ const charCode = char.charCodeAt(0);
1462
+ return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1463
+ }
1461
1464
  function isCharALetter(char) {
1462
1465
  return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
1463
1466
  }
1464
1467
  function isCharADigit(char) {
1465
1468
  return char >= "0" && char <= "9";
1466
1469
  }
1470
+ // we limit the max column to 3 letters and max row to 7 digits for performance reasons
1471
+ const MAX_COL = lettersToNumber("ZZZ");
1472
+ const MAX_ROW = 9999998;
1473
+ function consumeSpaces(chars) {
1474
+ while (chars.current === " ") {
1475
+ chars.advanceBy(1);
1476
+ }
1477
+ }
1478
+ function consumeLetters(chars) {
1479
+ if (chars.current === "$")
1480
+ chars.advanceBy(1);
1481
+ if (!chars.current || !isCharALetter(chars.current)) {
1482
+ return -1;
1483
+ }
1484
+ let colCoordinate = 0;
1485
+ while (chars.current && isCharALetter(chars.current)) {
1486
+ colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
1487
+ }
1488
+ return colCoordinate;
1489
+ }
1490
+ function consumeDigits(chars) {
1491
+ if (chars.current === "$")
1492
+ chars.advanceBy(1);
1493
+ if (!chars.current || !isCharADigit(chars.current)) {
1494
+ return -1;
1495
+ }
1496
+ let num = 0;
1497
+ while (chars.current && isCharADigit(chars.current)) {
1498
+ num = num * 10 + Number(chars.shift());
1499
+ }
1500
+ return num;
1501
+ }
1467
1502
  /**
1468
1503
  * Convert a "XC" coordinate to cartesian coordinates.
1469
1504
  *
@@ -1474,33 +1509,17 @@ function isCharADigit(char) {
1474
1509
  * Note: it also accepts lowercase coordinates, but not fixed references
1475
1510
  */
1476
1511
  function toCartesian(xc) {
1477
- xc = xc.trim();
1478
- let letterPart = "";
1479
- let numberPart = "";
1480
- let i = 0;
1481
- // Process letter part
1482
- if (xc[i] === "$")
1483
- i++;
1484
- while (i < xc.length && isCharALetter(xc[i])) {
1485
- letterPart += xc[i++];
1486
- }
1487
- if (letterPart.length === 0 || letterPart.length > 3) {
1488
- // limit to max 3 letters for performance reasons
1512
+ const chars = new TokenizingChars(xc);
1513
+ consumeSpaces(chars);
1514
+ const letterPart = consumeLetters(chars);
1515
+ if (letterPart === -1 || !chars.current) {
1489
1516
  throw new Error(`Invalid cell description: ${xc}`);
1490
1517
  }
1491
- // Process number part
1492
- if (xc[i] === "$")
1493
- i++;
1494
- while (i < xc.length && isCharADigit(xc[i])) {
1495
- numberPart += xc[i++];
1496
- }
1497
- if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
1498
- // limit to max 7 numbers for performance reasons
1499
- throw new Error(`Invalid cell description: ${xc}`);
1500
- }
1501
- const col = lettersToNumber(letterPart);
1502
- const row = Number(numberPart) - 1;
1503
- if (isNaN(row)) {
1518
+ const num = consumeDigits(chars);
1519
+ consumeSpaces(chars);
1520
+ const col = letterPart - 1;
1521
+ const row = num - 1;
1522
+ if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
1504
1523
  throw new Error(`Invalid cell description: ${xc}`);
1505
1524
  }
1506
1525
  return { col, row };
@@ -1912,67 +1931,6 @@ class LazyTranslatedString extends String {
1912
1931
  }
1913
1932
  }
1914
1933
 
1915
- /** Reference of a cell (eg. A1, $B$5) */
1916
- const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
1917
- // Same as above, but matches the exact string (nothing before or after)
1918
- const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
1919
- /** Reference of a column header (eg. A, AB, $A) */
1920
- const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
1921
- /** Reference of a row header (eg. 1, $1) */
1922
- const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
1923
- /** Reference of a column (eg. A, $CA, Sheet1!B) */
1924
- const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
1925
- /** Reference of a row (eg. 1, 59, Sheet1!9) */
1926
- const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
1927
- /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
1928
- const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
1929
- /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
1930
- const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
1931
- /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
1932
- const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
1933
- "(" +
1934
- [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
1935
- ")" +
1936
- /$/.source, "i");
1937
- /**
1938
- * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
1939
- */
1940
- function isColReference(xc) {
1941
- return colReference.test(xc);
1942
- }
1943
- /**
1944
- * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
1945
- */
1946
- function isRowReference(xc) {
1947
- return rowReference.test(xc);
1948
- }
1949
- function isColHeader(str) {
1950
- return colHeader.test(str);
1951
- }
1952
- function isRowHeader(str) {
1953
- return rowHeader.test(str);
1954
- }
1955
- /**
1956
- * Return true if the given xc is the reference of a single cell,
1957
- * without any specified sheet (e.g. A1)
1958
- */
1959
- function isSingleCellReference(xc) {
1960
- return singleCellReference.test(xc);
1961
- }
1962
- function splitReference(ref) {
1963
- if (!ref.includes("!")) {
1964
- return { xc: ref };
1965
- }
1966
- const parts = ref.split("!");
1967
- const xc = parts.pop();
1968
- const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
1969
- return { sheetName, xc };
1970
- }
1971
- /** Return a reference SheetName!xc from the given arguments */
1972
- function getFullReference(sheetName, xc) {
1973
- return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
1974
- }
1975
-
1976
1934
  /**
1977
1935
  * Convert from a cartesian reference to a Zone
1978
1936
  * The range boundaries will be kept in the same order as the
@@ -1990,63 +1948,55 @@ function getFullReference(sheetName, xc) {
1990
1948
  *
1991
1949
  */
1992
1950
  function toZoneWithoutBoundaryChanges(xc) {
1993
- if (xc.includes("!")) {
1994
- xc = xc.split("!").at(-1);
1995
- }
1996
- if (xc.includes("$")) {
1997
- xc = xc.replaceAll("$", "");
1998
- }
1999
- let firstRangePart = "";
2000
- let secondRangePart;
2001
- if (xc.includes(":")) {
2002
- [firstRangePart, secondRangePart] = xc.split(":");
2003
- firstRangePart = firstRangePart.trim();
2004
- secondRangePart = secondRangePart.trim();
2005
- }
2006
- else {
2007
- firstRangePart = xc.trim();
2008
- }
1951
+ const chars = new TokenizingChars(xc);
1952
+ consumeSpaces(chars);
1953
+ const sheetSeparatorIndex = xc.indexOf("!");
1954
+ if (sheetSeparatorIndex !== -1) {
1955
+ chars.advanceBy(sheetSeparatorIndex + 1);
1956
+ }
1957
+ const leftLetters = consumeLetters(chars);
1958
+ const leftNumbers = consumeDigits(chars);
2009
1959
  let top, bottom, left, right;
2010
1960
  let fullCol = false;
2011
1961
  let fullRow = false;
2012
1962
  let hasHeader = false;
2013
- if (isColReference(firstRangePart)) {
2014
- left = right = lettersToNumber(firstRangePart);
1963
+ if (leftNumbers === -1) {
1964
+ left = right = leftLetters - 1;
2015
1965
  top = bottom = 0;
2016
1966
  fullCol = true;
2017
1967
  }
2018
- else if (isRowReference(firstRangePart)) {
2019
- top = bottom = parseInt(firstRangePart, 10) - 1;
1968
+ else if (leftLetters === -1) {
1969
+ top = bottom = leftNumbers - 1;
2020
1970
  left = right = 0;
2021
1971
  fullRow = true;
2022
1972
  }
2023
1973
  else {
2024
- const c = toCartesian(firstRangePart);
2025
- left = right = c.col;
2026
- top = bottom = c.row;
1974
+ left = right = leftLetters - 1;
1975
+ top = bottom = leftNumbers - 1;
2027
1976
  hasHeader = true;
2028
1977
  }
2029
- if (secondRangePart) {
2030
- if (isColReference(secondRangePart)) {
2031
- right = lettersToNumber(secondRangePart);
1978
+ consumeSpaces(chars);
1979
+ if (chars.current === ":") {
1980
+ chars.advanceBy(1);
1981
+ consumeSpaces(chars);
1982
+ const rightLetters = consumeLetters(chars);
1983
+ const rightNumbers = consumeDigits(chars);
1984
+ if (rightNumbers === -1) {
1985
+ right = rightLetters - 1;
2032
1986
  fullCol = true;
2033
1987
  }
2034
- else if (isRowReference(secondRangePart)) {
2035
- bottom = parseInt(secondRangePart, 10) - 1;
1988
+ else if (rightLetters === -1) {
1989
+ bottom = rightNumbers - 1;
2036
1990
  fullRow = true;
2037
1991
  }
2038
1992
  else {
2039
- const c = toCartesian(secondRangePart);
2040
- right = c.col;
2041
- bottom = c.row;
1993
+ right = rightLetters - 1;
1994
+ bottom = rightNumbers - 1;
2042
1995
  top = fullCol ? bottom : top;
2043
1996
  left = fullRow ? right : left;
2044
1997
  hasHeader = true;
2045
1998
  }
2046
1999
  }
2047
- if (fullCol && fullRow) {
2048
- throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2049
- }
2050
2000
  const zone = {
2051
2001
  top,
2052
2002
  left,
@@ -2075,7 +2025,16 @@ function toZoneWithoutBoundaryChanges(xc) {
2075
2025
  */
2076
2026
  function toUnboundedZone(xc) {
2077
2027
  const zone = toZoneWithoutBoundaryChanges(xc);
2078
- return reorderZone(zone);
2028
+ const orderedZone = reorderZone(zone);
2029
+ const bottom = orderedZone.bottom;
2030
+ const right = orderedZone.right;
2031
+ if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
2032
+ throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
2033
+ }
2034
+ if (bottom === undefined && right === undefined) {
2035
+ throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2036
+ }
2037
+ return orderedZone;
2079
2038
  }
2080
2039
  /**
2081
2040
  * Convert from a cartesian reference to a Zone.
@@ -5796,6 +5755,67 @@ function scrollDelay(value) {
5796
5755
  return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
5797
5756
  }
5798
5757
 
5758
+ /** Reference of a cell (eg. A1, $B$5) */
5759
+ const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
5760
+ // Same as above, but matches the exact string (nothing before or after)
5761
+ const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
5762
+ /** Reference of a column header (eg. A, AB, $A) */
5763
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
5764
+ /** Reference of a row header (eg. 1, $1) */
5765
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
5766
+ /** Reference of a column (eg. A, $CA, Sheet1!B) */
5767
+ const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
5768
+ /** Reference of a row (eg. 1, 59, Sheet1!9) */
5769
+ const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
5770
+ /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
5771
+ const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
5772
+ /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
5773
+ const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
5774
+ /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
5775
+ const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
5776
+ "(" +
5777
+ [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
5778
+ ")" +
5779
+ /$/.source, "i");
5780
+ /**
5781
+ * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
5782
+ */
5783
+ function isColReference(xc) {
5784
+ return colReference.test(xc);
5785
+ }
5786
+ /**
5787
+ * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
5788
+ */
5789
+ function isRowReference(xc) {
5790
+ return rowReference.test(xc);
5791
+ }
5792
+ function isColHeader(str) {
5793
+ return colHeader.test(str);
5794
+ }
5795
+ function isRowHeader(str) {
5796
+ return rowHeader.test(str);
5797
+ }
5798
+ /**
5799
+ * Return true if the given xc is the reference of a single cell,
5800
+ * without any specified sheet (e.g. A1)
5801
+ */
5802
+ function isSingleCellReference(xc) {
5803
+ return singleCellReference.test(xc);
5804
+ }
5805
+ function splitReference(ref) {
5806
+ if (!ref.includes("!")) {
5807
+ return { xc: ref };
5808
+ }
5809
+ const parts = ref.split("!");
5810
+ const xc = parts.pop();
5811
+ const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
5812
+ return { sheetName, xc };
5813
+ }
5814
+ /** Return a reference SheetName!xc from the given arguments */
5815
+ function getFullReference(sheetName, xc) {
5816
+ return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
5817
+ }
5818
+
5799
5819
  class RangeImpl {
5800
5820
  getSheetSize;
5801
5821
  _zone;
@@ -39493,12 +39513,13 @@ class StandaloneComposerStore extends AbstractComposerStore {
39493
39513
  return providersDefinitions;
39494
39514
  }
39495
39515
  getComposerContent() {
39516
+ let content = this._currentContent;
39496
39517
  if (this.editionMode === "inactive") {
39497
39518
  // References in the content might not be linked to the current active sheet
39498
39519
  // We here force the sheet name prefix for all references that are not in
39499
39520
  // the current active sheet
39500
39521
  const defaultRangeSheetId = this.args().defaultRangeSheetId;
39501
- return rangeTokenize(this.args().content)
39522
+ content = rangeTokenize(this.args().content)
39502
39523
  .map((token) => {
39503
39524
  if (token.type === "REFERENCE") {
39504
39525
  const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
@@ -39508,7 +39529,7 @@ class StandaloneComposerStore extends AbstractComposerStore {
39508
39529
  })
39509
39530
  .join("");
39510
39531
  }
39511
- return this._currentContent;
39532
+ return localizeContent(content, this.getters.getLocale());
39512
39533
  }
39513
39534
  stopEdition() {
39514
39535
  this._stopEdition();
@@ -43111,6 +43132,9 @@ class PivotMeasureEditor extends Component {
43111
43132
  measure: this.props.measure,
43112
43133
  });
43113
43134
  }
43135
+ get isCalculatedMeasureInvalid() {
43136
+ return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
43137
+ }
43114
43138
  }
43115
43139
 
43116
43140
  css /* scss */ `
@@ -58445,10 +58469,9 @@ class Evaluator {
58445
58469
  return this.evaluatedCells.keysForSheet(sheetId);
58446
58470
  }
58447
58471
  getArrayFormulaSpreadingOn(position) {
58448
- const hasArrayFormulaResult = this.getEvaluatedCell(position).type !== CellValueType.empty &&
58449
- !this.getters.getCell(position)?.isFormula;
58450
- if (!hasArrayFormulaResult) {
58451
- return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
58472
+ const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
58473
+ if (isEmpty) {
58474
+ return undefined;
58452
58475
  }
58453
58476
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
58454
58477
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
@@ -74248,6 +74271,6 @@ const constants = {
74248
74271
  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 };
74249
74272
 
74250
74273
 
74251
- __info__.version = "18.0.28";
74252
- __info__.date = "2025-05-13T17:53:12.402Z";
74253
- __info__.hash = "b3088aa";
74274
+ __info__.version = "18.0.29";
74275
+ __info__.date = "2025-05-20T05:54:57.329Z";
74276
+ __info__.hash = "8213c0e";