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