@odoo/o-spreadsheet 18.2.12 → 18.2.13

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.2.12
6
- * @date 2025-05-13T17:52:23.989Z
7
- * @hash ba2ba9b
5
+ * @version 18.2.13
6
+ * @date 2025-05-20T05:57:00.985Z
7
+ * @hash 9872529
8
8
  */
9
9
 
10
10
  (function (exports, owl) {
@@ -1618,18 +1618,53 @@
1618
1618
  let result = 0;
1619
1619
  const l = letters.length;
1620
1620
  for (let i = 0; i < l; i++) {
1621
- const charCode = letters.charCodeAt(i);
1622
- const colIndex = charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1621
+ const colIndex = charToNumber(letters[i]);
1623
1622
  result = result * 26 + colIndex;
1624
1623
  }
1625
1624
  return result - 1;
1626
1625
  }
1626
+ function charToNumber(char) {
1627
+ const charCode = char.charCodeAt(0);
1628
+ return charCode >= 65 && charCode <= 90 ? charCode - 64 : charCode - 96;
1629
+ }
1627
1630
  function isCharALetter(char) {
1628
1631
  return (char >= "A" && char <= "Z") || (char >= "a" && char <= "z");
1629
1632
  }
1630
1633
  function isCharADigit(char) {
1631
1634
  return char >= "0" && char <= "9";
1632
1635
  }
1636
+ // we limit the max column to 3 letters and max row to 7 digits for performance reasons
1637
+ const MAX_COL = lettersToNumber("ZZZ");
1638
+ const MAX_ROW = 9999998;
1639
+ function consumeSpaces(chars) {
1640
+ while (chars.current === " ") {
1641
+ chars.advanceBy(1);
1642
+ }
1643
+ }
1644
+ function consumeLetters(chars) {
1645
+ if (chars.current === "$")
1646
+ chars.advanceBy(1);
1647
+ if (!chars.current || !isCharALetter(chars.current)) {
1648
+ return -1;
1649
+ }
1650
+ let colCoordinate = 0;
1651
+ while (chars.current && isCharALetter(chars.current)) {
1652
+ colCoordinate = colCoordinate * 26 + charToNumber(chars.shift());
1653
+ }
1654
+ return colCoordinate;
1655
+ }
1656
+ function consumeDigits(chars) {
1657
+ if (chars.current === "$")
1658
+ chars.advanceBy(1);
1659
+ if (!chars.current || !isCharADigit(chars.current)) {
1660
+ return -1;
1661
+ }
1662
+ let num = 0;
1663
+ while (chars.current && isCharADigit(chars.current)) {
1664
+ num = num * 10 + Number(chars.shift());
1665
+ }
1666
+ return num;
1667
+ }
1633
1668
  /**
1634
1669
  * Convert a "XC" coordinate to cartesian coordinates.
1635
1670
  *
@@ -1640,33 +1675,17 @@
1640
1675
  * Note: it also accepts lowercase coordinates, but not fixed references
1641
1676
  */
1642
1677
  function toCartesian(xc) {
1643
- xc = xc.trim();
1644
- let letterPart = "";
1645
- let numberPart = "";
1646
- let i = 0;
1647
- // Process letter part
1648
- if (xc[i] === "$")
1649
- i++;
1650
- while (i < xc.length && isCharALetter(xc[i])) {
1651
- letterPart += xc[i++];
1652
- }
1653
- if (letterPart.length === 0 || letterPart.length > 3) {
1654
- // limit to max 3 letters for performance reasons
1678
+ const chars = new TokenizingChars(xc);
1679
+ consumeSpaces(chars);
1680
+ const letterPart = consumeLetters(chars);
1681
+ if (letterPart === -1 || !chars.current) {
1655
1682
  throw new Error(`Invalid cell description: ${xc}`);
1656
1683
  }
1657
- // Process number part
1658
- if (xc[i] === "$")
1659
- i++;
1660
- while (i < xc.length && isCharADigit(xc[i])) {
1661
- numberPart += xc[i++];
1662
- }
1663
- if (i !== xc.length || numberPart.length === 0 || numberPart.length > 7) {
1664
- // limit to max 7 numbers for performance reasons
1665
- throw new Error(`Invalid cell description: ${xc}`);
1666
- }
1667
- const col = lettersToNumber(letterPart);
1668
- const row = Number(numberPart) - 1;
1669
- if (isNaN(row)) {
1684
+ const num = consumeDigits(chars);
1685
+ consumeSpaces(chars);
1686
+ const col = letterPart - 1;
1687
+ const row = num - 1;
1688
+ if (!chars.isOver() || col > MAX_COL || row > MAX_ROW) {
1670
1689
  throw new Error(`Invalid cell description: ${xc}`);
1671
1690
  }
1672
1691
  return { col, row };
@@ -2078,67 +2097,6 @@
2078
2097
  }
2079
2098
  }
2080
2099
 
2081
- /** Reference of a cell (eg. A1, $B$5) */
2082
- const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
2083
- // Same as above, but matches the exact string (nothing before or after)
2084
- const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
2085
- /** Reference of a column header (eg. A, AB, $A) */
2086
- const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
2087
- /** Reference of a row header (eg. 1, $1) */
2088
- const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
2089
- /** Reference of a column (eg. A, $CA, Sheet1!B) */
2090
- const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
2091
- /** Reference of a row (eg. 1, 59, Sheet1!9) */
2092
- const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
2093
- /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
2094
- const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
2095
- /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
2096
- const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
2097
- /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
2098
- const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
2099
- "(" +
2100
- [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
2101
- ")" +
2102
- /$/.source, "i");
2103
- /**
2104
- * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
2105
- */
2106
- function isColReference(xc) {
2107
- return colReference.test(xc);
2108
- }
2109
- /**
2110
- * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
2111
- */
2112
- function isRowReference(xc) {
2113
- return rowReference.test(xc);
2114
- }
2115
- function isColHeader(str) {
2116
- return colHeader.test(str);
2117
- }
2118
- function isRowHeader(str) {
2119
- return rowHeader.test(str);
2120
- }
2121
- /**
2122
- * Return true if the given xc is the reference of a single cell,
2123
- * without any specified sheet (e.g. A1)
2124
- */
2125
- function isSingleCellReference(xc) {
2126
- return singleCellReference.test(xc);
2127
- }
2128
- function splitReference(ref) {
2129
- if (!ref.includes("!")) {
2130
- return { xc: ref };
2131
- }
2132
- const parts = ref.split("!");
2133
- const xc = parts.pop();
2134
- const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
2135
- return { sheetName, xc };
2136
- }
2137
- /** Return a reference SheetName!xc from the given arguments */
2138
- function getFullReference(sheetName, xc) {
2139
- return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
2140
- }
2141
-
2142
2100
  /**
2143
2101
  * Convert from a cartesian reference to a Zone
2144
2102
  * The range boundaries will be kept in the same order as the
@@ -2156,63 +2114,55 @@
2156
2114
  *
2157
2115
  */
2158
2116
  function toZoneWithoutBoundaryChanges(xc) {
2159
- if (xc.includes("!")) {
2160
- xc = xc.split("!").at(-1);
2161
- }
2162
- if (xc.includes("$")) {
2163
- xc = xc.replaceAll("$", "");
2164
- }
2165
- let firstRangePart = "";
2166
- let secondRangePart;
2167
- if (xc.includes(":")) {
2168
- [firstRangePart, secondRangePart] = xc.split(":");
2169
- firstRangePart = firstRangePart.trim();
2170
- secondRangePart = secondRangePart.trim();
2171
- }
2172
- else {
2173
- firstRangePart = xc.trim();
2174
- }
2117
+ const chars = new TokenizingChars(xc);
2118
+ consumeSpaces(chars);
2119
+ const sheetSeparatorIndex = xc.indexOf("!");
2120
+ if (sheetSeparatorIndex !== -1) {
2121
+ chars.advanceBy(sheetSeparatorIndex + 1);
2122
+ }
2123
+ const leftLetters = consumeLetters(chars);
2124
+ const leftNumbers = consumeDigits(chars);
2175
2125
  let top, bottom, left, right;
2176
2126
  let fullCol = false;
2177
2127
  let fullRow = false;
2178
2128
  let hasHeader = false;
2179
- if (isColReference(firstRangePart)) {
2180
- left = right = lettersToNumber(firstRangePart);
2129
+ if (leftNumbers === -1) {
2130
+ left = right = leftLetters - 1;
2181
2131
  top = bottom = 0;
2182
2132
  fullCol = true;
2183
2133
  }
2184
- else if (isRowReference(firstRangePart)) {
2185
- top = bottom = parseInt(firstRangePart, 10) - 1;
2134
+ else if (leftLetters === -1) {
2135
+ top = bottom = leftNumbers - 1;
2186
2136
  left = right = 0;
2187
2137
  fullRow = true;
2188
2138
  }
2189
2139
  else {
2190
- const c = toCartesian(firstRangePart);
2191
- left = right = c.col;
2192
- top = bottom = c.row;
2140
+ left = right = leftLetters - 1;
2141
+ top = bottom = leftNumbers - 1;
2193
2142
  hasHeader = true;
2194
2143
  }
2195
- if (secondRangePart) {
2196
- if (isColReference(secondRangePart)) {
2197
- right = lettersToNumber(secondRangePart);
2144
+ consumeSpaces(chars);
2145
+ if (chars.current === ":") {
2146
+ chars.advanceBy(1);
2147
+ consumeSpaces(chars);
2148
+ const rightLetters = consumeLetters(chars);
2149
+ const rightNumbers = consumeDigits(chars);
2150
+ if (rightNumbers === -1) {
2151
+ right = rightLetters - 1;
2198
2152
  fullCol = true;
2199
2153
  }
2200
- else if (isRowReference(secondRangePart)) {
2201
- bottom = parseInt(secondRangePart, 10) - 1;
2154
+ else if (rightLetters === -1) {
2155
+ bottom = rightNumbers - 1;
2202
2156
  fullRow = true;
2203
2157
  }
2204
2158
  else {
2205
- const c = toCartesian(secondRangePart);
2206
- right = c.col;
2207
- bottom = c.row;
2159
+ right = rightLetters - 1;
2160
+ bottom = rightNumbers - 1;
2208
2161
  top = fullCol ? bottom : top;
2209
2162
  left = fullRow ? right : left;
2210
2163
  hasHeader = true;
2211
2164
  }
2212
2165
  }
2213
- if (fullCol && fullRow) {
2214
- throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2215
- }
2216
2166
  const zone = {
2217
2167
  top,
2218
2168
  left,
@@ -2241,7 +2191,16 @@
2241
2191
  */
2242
2192
  function toUnboundedZone(xc) {
2243
2193
  const zone = toZoneWithoutBoundaryChanges(xc);
2244
- return reorderZone(zone);
2194
+ const orderedZone = reorderZone(zone);
2195
+ const bottom = orderedZone.bottom;
2196
+ const right = orderedZone.right;
2197
+ if ((bottom !== undefined && bottom > MAX_ROW) || (right !== undefined && right > MAX_COL)) {
2198
+ throw new Error(`Range string out of bounds: ${xc}`); // limit the size of the zone for performance
2199
+ }
2200
+ if (bottom === undefined && right === undefined) {
2201
+ throw new Error("Wrong zone xc. The zone cannot be at the same time a full column and a full row");
2202
+ }
2203
+ return orderedZone;
2245
2204
  }
2246
2205
  /**
2247
2206
  * Convert from a cartesian reference to a Zone.
@@ -5975,6 +5934,67 @@
5975
5934
  return MIN_DELAY + (MAX_DELAY - MIN_DELAY) * Math.exp(-ACCELERATION * (value - 1));
5976
5935
  }
5977
5936
 
5937
+ /** Reference of a cell (eg. A1, $B$5) */
5938
+ const cellReference = new RegExp(/\$?([A-Z]{1,3})\$?([0-9]{1,7})/, "i");
5939
+ // Same as above, but matches the exact string (nothing before or after)
5940
+ const singleCellReference = new RegExp(/^\$?([A-Z]{1,3})\$?([0-9]{1,7})$/, "i");
5941
+ /** Reference of a column header (eg. A, AB, $A) */
5942
+ const colHeader = new RegExp(/^\$?([A-Z]{1,3})+$/, "i");
5943
+ /** Reference of a row header (eg. 1, $1) */
5944
+ const rowHeader = new RegExp(/^\$?([0-9]{1,7})+$/, "i");
5945
+ /** Reference of a column (eg. A, $CA, Sheet1!B) */
5946
+ const colReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([A-Z]{1,3})$/, "i");
5947
+ /** Reference of a row (eg. 1, 59, Sheet1!9) */
5948
+ const rowReference = new RegExp(/^\s*('.+'!|[^']+!)?\$?([0-9]{1,7})$/, "i");
5949
+ /** Reference of a normal range or a full row range (eg. A1:B1, 1:$5, $A2:5) */
5950
+ const fullRowXc = /(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*:\s*(\$?[A-Z]{1,3})?\$?[0-9]{1,7}\s*/i;
5951
+ /** Reference of a normal range or a column row range (eg. A1:B1, A:$B, $A1:C) */
5952
+ const fullColXc = /\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*:\s*\$?[A-Z]{1,3}(\$?[0-9]{1,7})?\s*/i;
5953
+ /** Reference of a cell or a range, it can be a bounded range, a full row or a full column */
5954
+ const rangeReference = new RegExp(/^\s*('.+'!|[^']+!)?/.source +
5955
+ "(" +
5956
+ [cellReference.source, fullRowXc.source, fullColXc.source].join("|") +
5957
+ ")" +
5958
+ /$/.source, "i");
5959
+ /**
5960
+ * Return true if the given xc is the reference of a column (e.g. A or AC or Sheet1!A)
5961
+ */
5962
+ function isColReference(xc) {
5963
+ return colReference.test(xc);
5964
+ }
5965
+ /**
5966
+ * Return true if the given xc is the reference of a column (e.g. 1 or Sheet1!1)
5967
+ */
5968
+ function isRowReference(xc) {
5969
+ return rowReference.test(xc);
5970
+ }
5971
+ function isColHeader(str) {
5972
+ return colHeader.test(str);
5973
+ }
5974
+ function isRowHeader(str) {
5975
+ return rowHeader.test(str);
5976
+ }
5977
+ /**
5978
+ * Return true if the given xc is the reference of a single cell,
5979
+ * without any specified sheet (e.g. A1)
5980
+ */
5981
+ function isSingleCellReference(xc) {
5982
+ return singleCellReference.test(xc);
5983
+ }
5984
+ function splitReference(ref) {
5985
+ if (!ref.includes("!")) {
5986
+ return { xc: ref };
5987
+ }
5988
+ const parts = ref.split("!");
5989
+ const xc = parts.pop();
5990
+ const sheetName = getUnquotedSheetName(parts.join("!")) || undefined;
5991
+ return { sheetName, xc };
5992
+ }
5993
+ /** Return a reference SheetName!xc from the given arguments */
5994
+ function getFullReference(sheetName, xc) {
5995
+ return sheetName !== undefined ? `${getCanonicalSymbolName(sheetName)}!${xc}` : xc;
5996
+ }
5997
+
5978
5998
  class RangeImpl {
5979
5999
  getSheetSize;
5980
6000
  _zone;
@@ -41158,12 +41178,13 @@ stores.inject(MyMetaStore, storeInstance);
41158
41178
  return res;
41159
41179
  }
41160
41180
  getComposerContent() {
41181
+ let content = this._currentContent;
41161
41182
  if (this.editionMode === "inactive") {
41162
41183
  // References in the content might not be linked to the current active sheet
41163
41184
  // We here force the sheet name prefix for all references that are not in
41164
41185
  // the current active sheet
41165
41186
  const defaultRangeSheetId = this.args().defaultRangeSheetId;
41166
- return rangeTokenize(this.args().content)
41187
+ content = rangeTokenize(this.args().content)
41167
41188
  .map((token) => {
41168
41189
  if (token.type === "REFERENCE") {
41169
41190
  const range = this.getters.getRangeFromSheetXC(defaultRangeSheetId, token.value);
@@ -41173,7 +41194,7 @@ stores.inject(MyMetaStore, storeInstance);
41173
41194
  })
41174
41195
  .join("");
41175
41196
  }
41176
- return this._currentContent;
41197
+ return localizeContent(content, this.getters.getLocale());
41177
41198
  }
41178
41199
  stopEdition() {
41179
41200
  this._stopEdition();
@@ -45448,6 +45469,9 @@ stores.inject(MyMetaStore, storeInstance);
45448
45469
  }
45449
45470
  return undefined;
45450
45471
  }
45472
+ get isCalculatedMeasureInvalid() {
45473
+ return this.env.model.getters.getMeasureCompiledFormula(this.props.measure).isBadExpression;
45474
+ }
45451
45475
  }
45452
45476
 
45453
45477
  css /* scss */ `
@@ -60950,10 +60974,9 @@ stores.inject(MyMetaStore, storeInstance);
60950
60974
  return this.evaluatedCells.keysForSheet(sheetId);
60951
60975
  }
60952
60976
  getArrayFormulaSpreadingOn(position) {
60953
- const hasArrayFormulaResult = this.getEvaluatedCell(position).type !== CellValueType.empty &&
60954
- !this.getters.getCell(position)?.isFormula;
60955
- if (!hasArrayFormulaResult) {
60956
- return this.spreadingRelations.isArrayFormula(position) ? position : undefined;
60977
+ const isEmpty = this.getEvaluatedCell(position).type === CellValueType.empty;
60978
+ if (isEmpty) {
60979
+ return undefined;
60957
60980
  }
60958
60981
  const arrayFormulas = this.spreadingRelations.searchFormulaPositionsSpreadingOn(position.sheetId, positionToZone(position));
60959
60982
  return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
@@ -76803,9 +76826,9 @@ stores.inject(MyMetaStore, storeInstance);
76803
76826
  exports.tokenize = tokenize;
76804
76827
 
76805
76828
 
76806
- __info__.version = "18.2.12";
76807
- __info__.date = "2025-05-13T17:52:23.989Z";
76808
- __info__.hash = "ba2ba9b";
76829
+ __info__.version = "18.2.13";
76830
+ __info__.date = "2025-05-20T05:57:00.985Z";
76831
+ __info__.hash = "9872529";
76809
76832
 
76810
76833
 
76811
76834
  })(this.o_spreadsheet = this.o_spreadsheet || {}, owl);