@odoo/o-spreadsheet 19.1.2 → 19.1.3

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,8 +3,8 @@
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
5
  * @version 19.1.0-alpha.3
6
- * @date 2026-01-07T16:20:59.139Z
7
- * @hash febc3e9
6
+ * @date 2026-01-14T10:01:54.190Z
7
+ * @hash 52a3e52
8
8
  */
9
9
 
10
10
  (function (exports) {
@@ -15076,9 +15076,10 @@
15076
15076
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15077
15077
  }
15078
15078
  }
15079
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15079
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15080
15080
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15081
15081
  const dependencies = [];
15082
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15082
15083
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15083
15084
  const { sheetId, zone } = coreDefinition.dataSet;
15084
15085
  const xc = zoneToXc(zone);
@@ -15095,8 +15096,7 @@
15095
15096
  }
15096
15097
  for (const measure of forMeasures) {
15097
15098
  if (measure.computedBy) {
15098
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15099
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
15099
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15100
15100
  }
15101
15101
  }
15102
15102
  const originPosition = evalContext.__originCellPosition;
@@ -15593,7 +15593,7 @@
15593
15593
  assertDomainLength(domainArgs);
15594
15594
  const pivot = this.getters.getPivot(pivotId);
15595
15595
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
15596
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
15596
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
15597
15597
  pivot.init({ reload: pivot.needsReevaluation });
15598
15598
  const error = pivot.assertIsValid({ throwOnError: false });
15599
15599
  if (error) {
@@ -15626,8 +15626,7 @@
15626
15626
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
15627
15627
  assertDomainLength(domainArgs);
15628
15628
  const pivot = this.getters.getPivot(_pivotId);
15629
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
15630
- addPivotDependencies(this, coreDefinition, []);
15629
+ addPivotDependencies(this, _pivotId, []);
15631
15630
  pivot.init({ reload: pivot.needsReevaluation });
15632
15631
  const error = pivot.assertIsValid({ throwOnError: false });
15633
15632
  if (error) {
@@ -15679,7 +15678,7 @@
15679
15678
  if (pivotStyle.numberOfColumns < 0) {
15680
15679
  return new EvaluationError(_t("The number of columns must be positive."));
15681
15680
  }
15682
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
15681
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
15683
15682
  pivot.init({ reload: pivot.needsReevaluation });
15684
15683
  const error = pivot.assertIsValid({ throwOnError: false });
15685
15684
  if (error) {
@@ -22785,6 +22784,403 @@
22785
22784
  */
22786
22785
  const DEFAULT_SYSTEM_COLOR = "FF000000";
22787
22786
 
22787
+ const globalReverseLookup$1 = new WeakMap();
22788
+ const globalIdCounter = new WeakMap();
22789
+ /**
22790
+ * Get the id of the given item (its key in the given dictionary).
22791
+ * If the given item does not exist in the dictionary, it creates one with a new id.
22792
+ */
22793
+ function getItemId(item, itemsDic) {
22794
+ if (!globalReverseLookup$1.has(itemsDic)) {
22795
+ globalReverseLookup$1.set(itemsDic, new Map());
22796
+ globalIdCounter.set(itemsDic, 0);
22797
+ }
22798
+ const reverseLookup = globalReverseLookup$1.get(itemsDic);
22799
+ const canonical = getCanonicalRepresentation(item);
22800
+ if (reverseLookup.has(canonical)) {
22801
+ const id = reverseLookup.get(canonical);
22802
+ itemsDic[id] = item;
22803
+ return id;
22804
+ }
22805
+ // Generate new Id if the item didn't exist in the dictionary
22806
+ const newId = globalIdCounter.get(itemsDic) + 1;
22807
+ reverseLookup.set(canonical, newId);
22808
+ globalIdCounter.set(itemsDic, newId);
22809
+ itemsDic[newId] = item;
22810
+ return newId;
22811
+ }
22812
+ function groupItemIdsByZones(positionsByItemId) {
22813
+ const result = {};
22814
+ for (const itemId in positionsByItemId) {
22815
+ const zones = recomputeZones(positionsByItemId[itemId].map(positionToZone));
22816
+ for (const zone of zones) {
22817
+ result[zoneToXc(zone)] = Number(itemId);
22818
+ }
22819
+ }
22820
+ return result;
22821
+ }
22822
+ function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
22823
+ for (const zoneXc in itemIdsByZones) {
22824
+ const zone = toZone(zoneXc);
22825
+ const itemId = itemIdsByZones[zoneXc];
22826
+ for (let row = zone.top; row <= zone.bottom; row++) {
22827
+ for (let col = zone.left; col <= zone.right; col++) {
22828
+ const position = { sheetId, col, row };
22829
+ yield [position, itemId];
22830
+ }
22831
+ }
22832
+ }
22833
+ }
22834
+ function getCanonicalRepresentation(item) {
22835
+ if (item === null)
22836
+ return "null";
22837
+ if (item === undefined)
22838
+ return "undefined";
22839
+ if (typeof item !== "object")
22840
+ return String(item);
22841
+ if (Array.isArray(item)) {
22842
+ const len = item.length;
22843
+ let result = "[";
22844
+ for (let i = 0; i < len; i++) {
22845
+ if (i > 0)
22846
+ result += ",";
22847
+ result += getCanonicalRepresentation(item[i]);
22848
+ }
22849
+ return result + "]";
22850
+ }
22851
+ const keys = Object.keys(item).sort();
22852
+ let repr = "{";
22853
+ for (const key of keys) {
22854
+ if (item[key] !== undefined) {
22855
+ repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
22856
+ }
22857
+ }
22858
+ repr += "}";
22859
+ return repr;
22860
+ }
22861
+
22862
+ // -------------------------------------
22863
+ // CF HELPERS
22864
+ // -------------------------------------
22865
+ /**
22866
+ * Convert the conditional formatting o-spreadsheet operator to
22867
+ * the corresponding excel operator.
22868
+ * */
22869
+ function convertOperator(operator) {
22870
+ switch (operator) {
22871
+ case "isNotEmpty":
22872
+ return "notContainsBlanks";
22873
+ case "isEmpty":
22874
+ return "containsBlanks";
22875
+ case "notContainsText":
22876
+ return "notContainsBlanks";
22877
+ case "containsText":
22878
+ return "containsText";
22879
+ case "beginsWithText":
22880
+ return "beginsWith";
22881
+ case "endsWithText":
22882
+ return "endsWith";
22883
+ case "isGreaterThan":
22884
+ return "greaterThan";
22885
+ case "isGreaterOrEqualTo":
22886
+ return "greaterThanOrEqual";
22887
+ case "isLessThan":
22888
+ return "lessThan";
22889
+ case "isLessOrEqualTo":
22890
+ return "lessThanOrEqual";
22891
+ case "isBetween":
22892
+ return "between";
22893
+ case "isNotBetween":
22894
+ return "notBetween";
22895
+ case "isEqual":
22896
+ return "equal";
22897
+ case "isNotEqual":
22898
+ return "notEqual";
22899
+ case "customFormula":
22900
+ return "";
22901
+ case "dateIs":
22902
+ return "";
22903
+ case "dateIsBefore":
22904
+ return "lessThan";
22905
+ case "dateIsAfter":
22906
+ return "greaterThan";
22907
+ case "dateIsOnOrAfter":
22908
+ return "greaterThanOrEqual";
22909
+ case "dateIsOnOrBefore":
22910
+ return "lessThanOrEqual";
22911
+ }
22912
+ }
22913
+ // -------------------------------------
22914
+ // WORKSHEET HELPERS
22915
+ // -------------------------------------
22916
+ function getCellType(value) {
22917
+ switch (typeof value) {
22918
+ case "boolean":
22919
+ return "b";
22920
+ case "string":
22921
+ return "str";
22922
+ case "number":
22923
+ return "n";
22924
+ default:
22925
+ return undefined;
22926
+ }
22927
+ }
22928
+ function convertHeightToExcel(height) {
22929
+ return Math.round(HEIGHT_FACTOR * height * 100) / 100;
22930
+ }
22931
+ function convertWidthToExcel(width) {
22932
+ return Math.round(WIDTH_FACTOR * width * 100) / 100;
22933
+ }
22934
+ function convertHeightFromExcel(height) {
22935
+ if (!height)
22936
+ return height;
22937
+ return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
22938
+ }
22939
+ function convertWidthFromExcel(width) {
22940
+ if (!width)
22941
+ return width;
22942
+ return Math.round((width / WIDTH_FACTOR) * 100) / 100;
22943
+ }
22944
+ function extractStyle(data, content, styleId, formatId, borderId) {
22945
+ const style = styleId ? data.styles[styleId] : {};
22946
+ const format = formatId ? data.formats[formatId] : undefined;
22947
+ const styles = {
22948
+ font: {
22949
+ size: style?.fontSize || DEFAULT_FONT_SIZE,
22950
+ color: { rgb: style?.textColor ? style.textColor : "000000" },
22951
+ family: 2,
22952
+ name: "Arial",
22953
+ },
22954
+ fill: style?.fillColor
22955
+ ? {
22956
+ fgColor: { rgb: style.fillColor },
22957
+ }
22958
+ : { reservedAttribute: "none" },
22959
+ numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
22960
+ border: borderId || 0,
22961
+ alignment: {
22962
+ horizontal: style.align,
22963
+ vertical: style.verticalAlign
22964
+ ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
22965
+ : undefined,
22966
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
22967
+ textRotation: style.rotation ? rotationToXLSX(style.rotation) : undefined,
22968
+ },
22969
+ };
22970
+ styles.font["strike"] = !!style?.strikethrough || undefined;
22971
+ styles.font["underline"] = !!style?.underline || undefined;
22972
+ styles.font["bold"] = !!style?.bold || undefined;
22973
+ styles.font["italic"] = !!style?.italic || undefined;
22974
+ return styles;
22975
+ }
22976
+ function rotationToXLSX(rad) {
22977
+ let deg = Math.round((-rad / Math.PI) * 180) % 180;
22978
+ if (deg > 90) {
22979
+ deg -= 180;
22980
+ }
22981
+ else if (deg < -90) {
22982
+ deg += 180;
22983
+ }
22984
+ if (deg >= 0) {
22985
+ return deg;
22986
+ }
22987
+ else {
22988
+ return 90 - deg;
22989
+ }
22990
+ }
22991
+ function rotationFromXLSX(deg) {
22992
+ if (deg <= 90) {
22993
+ return -(deg / 180) * Math.PI;
22994
+ }
22995
+ else {
22996
+ return (-(90 - deg) / 180) * Math.PI;
22997
+ }
22998
+ }
22999
+ function normalizeStyle(construct, styles) {
23000
+ // Normalize this
23001
+ const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
23002
+ const style = {
23003
+ fontId: pushElement(styles.font, construct.fonts),
23004
+ fillId: pushElement(styles.fill, construct.fills),
23005
+ borderId: styles.border,
23006
+ numFmtId,
23007
+ alignment: {
23008
+ vertical: styles.alignment.vertical,
23009
+ horizontal: styles.alignment.horizontal,
23010
+ wrapText: styles.alignment.wrapText,
23011
+ textRotation: styles.alignment.textRotation,
23012
+ },
23013
+ };
23014
+ return pushElement(style, construct.styles);
23015
+ }
23016
+ function convertFormat(format, numFmtStructure) {
23017
+ if (!format) {
23018
+ return 0;
23019
+ }
23020
+ let formatId = XLSX_FORMAT_MAP[format.format];
23021
+ if (!formatId) {
23022
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
23023
+ }
23024
+ return formatId;
23025
+ }
23026
+ /**
23027
+ * Add a relation to the given file and return its id.
23028
+ */
23029
+ function addRelsToFile(relsFiles, path, rel) {
23030
+ const relsFile = relsFiles.find((file) => file.path === path);
23031
+ // the id is a one-based int casted as string
23032
+ let id;
23033
+ if (!relsFile) {
23034
+ id = "rId1";
23035
+ relsFiles.push({ path, rels: [{ ...rel, id }] });
23036
+ }
23037
+ else {
23038
+ id = `rId${(relsFile.rels.length + 1).toString()}`;
23039
+ relsFile.rels.push({
23040
+ ...rel,
23041
+ id,
23042
+ });
23043
+ }
23044
+ return id;
23045
+ }
23046
+ const globalReverseLookup = new WeakMap();
23047
+ function pushElement(property, propertyList) {
23048
+ let reverseLookup = globalReverseLookup.get(propertyList);
23049
+ if (!reverseLookup) {
23050
+ reverseLookup = new Map();
23051
+ for (let i = 0; i < propertyList.length; i++) {
23052
+ const canonical = getCanonicalRepresentation(propertyList[i]);
23053
+ reverseLookup.set(canonical, i);
23054
+ }
23055
+ globalReverseLookup.set(propertyList, reverseLookup);
23056
+ }
23057
+ const canonical = getCanonicalRepresentation(property);
23058
+ if (reverseLookup.has(canonical)) {
23059
+ return reverseLookup.get(canonical);
23060
+ }
23061
+ const maxId = propertyList.length;
23062
+ propertyList.push(property);
23063
+ reverseLookup.set(canonical, maxId);
23064
+ return maxId;
23065
+ }
23066
+ /**
23067
+ * Convert a chart o-spreadsheet id to a xlsx id which
23068
+ * are unsigned integers (starting from 1).
23069
+ */
23070
+ function convertChartId(chartId, construct) {
23071
+ const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
23072
+ if (xlsxId === -1) {
23073
+ construct.chartIds.push(chartId);
23074
+ return construct.chartIds.length;
23075
+ }
23076
+ return xlsxId + 1;
23077
+ }
23078
+ const imageIds = [];
23079
+ /**
23080
+ * Convert a image o-spreadsheet id to a xlsx id which
23081
+ * are unsigned integers (starting from 1).
23082
+ */
23083
+ function convertImageId(imageId) {
23084
+ const xlsxId = imageIds.findIndex((id) => id === imageId);
23085
+ if (xlsxId === -1) {
23086
+ imageIds.push(imageId);
23087
+ return imageIds.length;
23088
+ }
23089
+ return xlsxId + 1;
23090
+ }
23091
+ /**
23092
+ * Convert a value expressed in dot to EMU.
23093
+ * EMU = English Metrical Unit
23094
+ * There are 914400 EMU per inch.
23095
+ *
23096
+ * /!\ A value expressed in EMU cannot be fractional.
23097
+ * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
23098
+ */
23099
+ function convertDotValueToEMU(value) {
23100
+ const DPI = 96;
23101
+ return Math.round((value * 914400) / DPI);
23102
+ }
23103
+ function getRangeSize(reference, defaultSheetIndex, data) {
23104
+ let xc = reference;
23105
+ let sheetName = undefined;
23106
+ ({ xc, sheetName } = splitReference(reference));
23107
+ let rangeSheetIndex;
23108
+ if (sheetName) {
23109
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
23110
+ if (index < 0) {
23111
+ throw new Error("Unable to find a sheet with the name " + sheetName);
23112
+ }
23113
+ rangeSheetIndex = index;
23114
+ }
23115
+ else {
23116
+ rangeSheetIndex = Number(defaultSheetIndex);
23117
+ }
23118
+ const zone = toUnboundedZone(xc);
23119
+ if (zone.right === undefined) {
23120
+ zone.right = data.sheets[rangeSheetIndex].colNumber;
23121
+ }
23122
+ if (zone.bottom === undefined) {
23123
+ zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
23124
+ }
23125
+ return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
23126
+ }
23127
+ function convertEMUToDotValue(value) {
23128
+ const DPI = 96;
23129
+ return Math.round((value * DPI) / 914400);
23130
+ }
23131
+ /**
23132
+ * Get the position of the start of a column in Excel (in px).
23133
+ */
23134
+ function getColPosition(colIndex, sheetData) {
23135
+ let position = 0;
23136
+ for (let i = 0; i < colIndex; i++) {
23137
+ const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
23138
+ if (colAtIndex?.width) {
23139
+ position += colAtIndex.width;
23140
+ }
23141
+ else if (sheetData.sheetFormat?.defaultColWidth) {
23142
+ position += sheetData.sheetFormat.defaultColWidth;
23143
+ }
23144
+ else {
23145
+ position += EXCEL_DEFAULT_COL_WIDTH;
23146
+ }
23147
+ }
23148
+ return position / WIDTH_FACTOR;
23149
+ }
23150
+ /**
23151
+ * Get the position of the start of a row in Excel (in px).
23152
+ */
23153
+ function getRowPosition(rowIndex, sheetData) {
23154
+ let position = 0;
23155
+ for (let i = 0; i < rowIndex; i++) {
23156
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
23157
+ if (rowAtIndex?.height) {
23158
+ position += rowAtIndex.height;
23159
+ }
23160
+ else if (sheetData.sheetFormat?.defaultRowHeight) {
23161
+ position += sheetData.sheetFormat.defaultRowHeight;
23162
+ }
23163
+ else {
23164
+ position += EXCEL_DEFAULT_ROW_HEIGHT;
23165
+ }
23166
+ }
23167
+ return position / HEIGHT_FACTOR;
23168
+ }
23169
+ /**
23170
+ * Convert the o-spreadsheet data validation decimal
23171
+ * criterion type to the corresponding excel operator.
23172
+ */
23173
+ function convertDecimalCriterionTypeToExcelOperator(operator) {
23174
+ return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
23175
+ }
23176
+ /**
23177
+ * Convert the o-spreadsheet data validation date
23178
+ * criterion type to the corresponding excel operator.
23179
+ */
23180
+ function convertDateCriterionTypeToExcelOperator(operator) {
23181
+ return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
23182
+ }
23183
+
22788
23184
  const XLSX_DATE_FORMAT_REGEX = /^(yy|yyyy|m{1,5}|d{1,4}|h{1,2}|s{1,2}|am\/pm|a\/m|\s|-|\/|\.|:)+$/i;
22789
23185
  /**
22790
23186
  * Convert excel format to o_spreadsheet format
@@ -22884,6 +23280,9 @@
22884
23280
  align: styleStruct.alignment?.horizontal
22885
23281
  ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
22886
23282
  : undefined,
23283
+ rotation: styleStruct.alignment?.textRotation
23284
+ ? rotationFromXLSX(styleStruct.alignment.textRotation)
23285
+ : undefined,
22887
23286
  // In xlsx fills, bgColor is the color of the fill, and fgColor is the color of the pattern above the background, except in solid fills
22888
23287
  fillColor: styleStruct.fillStyle?.patternType === "solid"
22889
23288
  ? convertColor(styleStruct.fillStyle?.fgColor)
@@ -23183,378 +23582,6 @@
23183
23582
  }
23184
23583
  }
23185
23584
 
23186
- const globalReverseLookup$1 = new WeakMap();
23187
- const globalIdCounter = new WeakMap();
23188
- /**
23189
- * Get the id of the given item (its key in the given dictionary).
23190
- * If the given item does not exist in the dictionary, it creates one with a new id.
23191
- */
23192
- function getItemId(item, itemsDic) {
23193
- if (!globalReverseLookup$1.has(itemsDic)) {
23194
- globalReverseLookup$1.set(itemsDic, new Map());
23195
- globalIdCounter.set(itemsDic, 0);
23196
- }
23197
- const reverseLookup = globalReverseLookup$1.get(itemsDic);
23198
- const canonical = getCanonicalRepresentation(item);
23199
- if (reverseLookup.has(canonical)) {
23200
- const id = reverseLookup.get(canonical);
23201
- itemsDic[id] = item;
23202
- return id;
23203
- }
23204
- // Generate new Id if the item didn't exist in the dictionary
23205
- const newId = globalIdCounter.get(itemsDic) + 1;
23206
- reverseLookup.set(canonical, newId);
23207
- globalIdCounter.set(itemsDic, newId);
23208
- itemsDic[newId] = item;
23209
- return newId;
23210
- }
23211
- function groupItemIdsByZones(positionsByItemId) {
23212
- const result = {};
23213
- for (const itemId in positionsByItemId) {
23214
- const zones = recomputeZones(positionsByItemId[itemId].map(positionToZone));
23215
- for (const zone of zones) {
23216
- result[zoneToXc(zone)] = Number(itemId);
23217
- }
23218
- }
23219
- return result;
23220
- }
23221
- function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
23222
- for (const zoneXc in itemIdsByZones) {
23223
- const zone = toZone(zoneXc);
23224
- const itemId = itemIdsByZones[zoneXc];
23225
- for (let row = zone.top; row <= zone.bottom; row++) {
23226
- for (let col = zone.left; col <= zone.right; col++) {
23227
- const position = { sheetId, col, row };
23228
- yield [position, itemId];
23229
- }
23230
- }
23231
- }
23232
- }
23233
- function getCanonicalRepresentation(item) {
23234
- if (item === null)
23235
- return "null";
23236
- if (item === undefined)
23237
- return "undefined";
23238
- if (typeof item !== "object")
23239
- return String(item);
23240
- if (Array.isArray(item)) {
23241
- const len = item.length;
23242
- let result = "[";
23243
- for (let i = 0; i < len; i++) {
23244
- if (i > 0)
23245
- result += ",";
23246
- result += getCanonicalRepresentation(item[i]);
23247
- }
23248
- return result + "]";
23249
- }
23250
- const keys = Object.keys(item).sort();
23251
- let repr = "{";
23252
- for (const key of keys) {
23253
- if (item[key] !== undefined) {
23254
- repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
23255
- }
23256
- }
23257
- repr += "}";
23258
- return repr;
23259
- }
23260
-
23261
- // -------------------------------------
23262
- // CF HELPERS
23263
- // -------------------------------------
23264
- /**
23265
- * Convert the conditional formatting o-spreadsheet operator to
23266
- * the corresponding excel operator.
23267
- * */
23268
- function convertOperator(operator) {
23269
- switch (operator) {
23270
- case "isNotEmpty":
23271
- return "notContainsBlanks";
23272
- case "isEmpty":
23273
- return "containsBlanks";
23274
- case "notContainsText":
23275
- return "notContainsBlanks";
23276
- case "containsText":
23277
- return "containsText";
23278
- case "beginsWithText":
23279
- return "beginsWith";
23280
- case "endsWithText":
23281
- return "endsWith";
23282
- case "isGreaterThan":
23283
- return "greaterThan";
23284
- case "isGreaterOrEqualTo":
23285
- return "greaterThanOrEqual";
23286
- case "isLessThan":
23287
- return "lessThan";
23288
- case "isLessOrEqualTo":
23289
- return "lessThanOrEqual";
23290
- case "isBetween":
23291
- return "between";
23292
- case "isNotBetween":
23293
- return "notBetween";
23294
- case "isEqual":
23295
- return "equal";
23296
- case "isNotEqual":
23297
- return "notEqual";
23298
- case "customFormula":
23299
- return "";
23300
- case "dateIs":
23301
- return "";
23302
- case "dateIsBefore":
23303
- return "lessThan";
23304
- case "dateIsAfter":
23305
- return "greaterThan";
23306
- case "dateIsOnOrAfter":
23307
- return "greaterThanOrEqual";
23308
- case "dateIsOnOrBefore":
23309
- return "lessThanOrEqual";
23310
- }
23311
- }
23312
- // -------------------------------------
23313
- // WORKSHEET HELPERS
23314
- // -------------------------------------
23315
- function getCellType(value) {
23316
- switch (typeof value) {
23317
- case "boolean":
23318
- return "b";
23319
- case "string":
23320
- return "str";
23321
- case "number":
23322
- return "n";
23323
- default:
23324
- return undefined;
23325
- }
23326
- }
23327
- function convertHeightToExcel(height) {
23328
- return Math.round(HEIGHT_FACTOR * height * 100) / 100;
23329
- }
23330
- function convertWidthToExcel(width) {
23331
- return Math.round(WIDTH_FACTOR * width * 100) / 100;
23332
- }
23333
- function convertHeightFromExcel(height) {
23334
- if (!height)
23335
- return height;
23336
- return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
23337
- }
23338
- function convertWidthFromExcel(width) {
23339
- if (!width)
23340
- return width;
23341
- return Math.round((width / WIDTH_FACTOR) * 100) / 100;
23342
- }
23343
- function extractStyle(data, content, styleId, formatId, borderId) {
23344
- const style = styleId ? data.styles[styleId] : {};
23345
- const format = formatId ? data.formats[formatId] : undefined;
23346
- const styles = {
23347
- font: {
23348
- size: style?.fontSize || DEFAULT_FONT_SIZE,
23349
- color: { rgb: style?.textColor ? style.textColor : "000000" },
23350
- family: 2,
23351
- name: "Arial",
23352
- },
23353
- fill: style?.fillColor
23354
- ? {
23355
- fgColor: { rgb: style.fillColor },
23356
- }
23357
- : { reservedAttribute: "none" },
23358
- numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
23359
- border: borderId || 0,
23360
- alignment: {
23361
- horizontal: style.align,
23362
- vertical: style.verticalAlign
23363
- ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
23364
- : undefined,
23365
- wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
23366
- },
23367
- };
23368
- styles.font["strike"] = !!style?.strikethrough || undefined;
23369
- styles.font["underline"] = !!style?.underline || undefined;
23370
- styles.font["bold"] = !!style?.bold || undefined;
23371
- styles.font["italic"] = !!style?.italic || undefined;
23372
- return styles;
23373
- }
23374
- function normalizeStyle(construct, styles) {
23375
- // Normalize this
23376
- const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
23377
- const style = {
23378
- fontId: pushElement(styles.font, construct.fonts),
23379
- fillId: pushElement(styles.fill, construct.fills),
23380
- borderId: styles.border,
23381
- numFmtId,
23382
- alignment: {
23383
- vertical: styles.alignment.vertical,
23384
- horizontal: styles.alignment.horizontal,
23385
- wrapText: styles.alignment.wrapText,
23386
- },
23387
- };
23388
- return pushElement(style, construct.styles);
23389
- }
23390
- function convertFormat(format, numFmtStructure) {
23391
- if (!format) {
23392
- return 0;
23393
- }
23394
- let formatId = XLSX_FORMAT_MAP[format.format];
23395
- if (!formatId) {
23396
- formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
23397
- }
23398
- return formatId;
23399
- }
23400
- /**
23401
- * Add a relation to the given file and return its id.
23402
- */
23403
- function addRelsToFile(relsFiles, path, rel) {
23404
- const relsFile = relsFiles.find((file) => file.path === path);
23405
- // the id is a one-based int casted as string
23406
- let id;
23407
- if (!relsFile) {
23408
- id = "rId1";
23409
- relsFiles.push({ path, rels: [{ ...rel, id }] });
23410
- }
23411
- else {
23412
- id = `rId${(relsFile.rels.length + 1).toString()}`;
23413
- relsFile.rels.push({
23414
- ...rel,
23415
- id,
23416
- });
23417
- }
23418
- return id;
23419
- }
23420
- const globalReverseLookup = new WeakMap();
23421
- function pushElement(property, propertyList) {
23422
- let reverseLookup = globalReverseLookup.get(propertyList);
23423
- if (!reverseLookup) {
23424
- reverseLookup = new Map();
23425
- for (let i = 0; i < propertyList.length; i++) {
23426
- const canonical = getCanonicalRepresentation(propertyList[i]);
23427
- reverseLookup.set(canonical, i);
23428
- }
23429
- globalReverseLookup.set(propertyList, reverseLookup);
23430
- }
23431
- const canonical = getCanonicalRepresentation(property);
23432
- if (reverseLookup.has(canonical)) {
23433
- return reverseLookup.get(canonical);
23434
- }
23435
- const maxId = propertyList.length;
23436
- propertyList.push(property);
23437
- reverseLookup.set(canonical, maxId);
23438
- return maxId;
23439
- }
23440
- /**
23441
- * Convert a chart o-spreadsheet id to a xlsx id which
23442
- * are unsigned integers (starting from 1).
23443
- */
23444
- function convertChartId(chartId, construct) {
23445
- const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
23446
- if (xlsxId === -1) {
23447
- construct.chartIds.push(chartId);
23448
- return construct.chartIds.length;
23449
- }
23450
- return xlsxId + 1;
23451
- }
23452
- const imageIds = [];
23453
- /**
23454
- * Convert a image o-spreadsheet id to a xlsx id which
23455
- * are unsigned integers (starting from 1).
23456
- */
23457
- function convertImageId(imageId) {
23458
- const xlsxId = imageIds.findIndex((id) => id === imageId);
23459
- if (xlsxId === -1) {
23460
- imageIds.push(imageId);
23461
- return imageIds.length;
23462
- }
23463
- return xlsxId + 1;
23464
- }
23465
- /**
23466
- * Convert a value expressed in dot to EMU.
23467
- * EMU = English Metrical Unit
23468
- * There are 914400 EMU per inch.
23469
- *
23470
- * /!\ A value expressed in EMU cannot be fractional.
23471
- * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
23472
- */
23473
- function convertDotValueToEMU(value) {
23474
- const DPI = 96;
23475
- return Math.round((value * 914400) / DPI);
23476
- }
23477
- function getRangeSize(reference, defaultSheetIndex, data) {
23478
- let xc = reference;
23479
- let sheetName = undefined;
23480
- ({ xc, sheetName } = splitReference(reference));
23481
- let rangeSheetIndex;
23482
- if (sheetName) {
23483
- const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
23484
- if (index < 0) {
23485
- throw new Error("Unable to find a sheet with the name " + sheetName);
23486
- }
23487
- rangeSheetIndex = index;
23488
- }
23489
- else {
23490
- rangeSheetIndex = Number(defaultSheetIndex);
23491
- }
23492
- const zone = toUnboundedZone(xc);
23493
- if (zone.right === undefined) {
23494
- zone.right = data.sheets[rangeSheetIndex].colNumber;
23495
- }
23496
- if (zone.bottom === undefined) {
23497
- zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
23498
- }
23499
- return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
23500
- }
23501
- function convertEMUToDotValue(value) {
23502
- const DPI = 96;
23503
- return Math.round((value * DPI) / 914400);
23504
- }
23505
- /**
23506
- * Get the position of the start of a column in Excel (in px).
23507
- */
23508
- function getColPosition(colIndex, sheetData) {
23509
- let position = 0;
23510
- for (let i = 0; i < colIndex; i++) {
23511
- const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
23512
- if (colAtIndex?.width) {
23513
- position += colAtIndex.width;
23514
- }
23515
- else if (sheetData.sheetFormat?.defaultColWidth) {
23516
- position += sheetData.sheetFormat.defaultColWidth;
23517
- }
23518
- else {
23519
- position += EXCEL_DEFAULT_COL_WIDTH;
23520
- }
23521
- }
23522
- return position / WIDTH_FACTOR;
23523
- }
23524
- /**
23525
- * Get the position of the start of a row in Excel (in px).
23526
- */
23527
- function getRowPosition(rowIndex, sheetData) {
23528
- let position = 0;
23529
- for (let i = 0; i < rowIndex; i++) {
23530
- const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
23531
- if (rowAtIndex?.height) {
23532
- position += rowAtIndex.height;
23533
- }
23534
- else if (sheetData.sheetFormat?.defaultRowHeight) {
23535
- position += sheetData.sheetFormat.defaultRowHeight;
23536
- }
23537
- else {
23538
- position += EXCEL_DEFAULT_ROW_HEIGHT;
23539
- }
23540
- }
23541
- return position / HEIGHT_FACTOR;
23542
- }
23543
- /**
23544
- * Convert the o-spreadsheet data validation decimal
23545
- * criterion type to the corresponding excel operator.
23546
- */
23547
- function convertDecimalCriterionTypeToExcelOperator(operator) {
23548
- return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
23549
- }
23550
- /**
23551
- * Convert the o-spreadsheet data validation date
23552
- * criterion type to the corresponding excel operator.
23553
- */
23554
- function convertDateCriterionTypeToExcelOperator(operator) {
23555
- return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
23556
- }
23557
-
23558
23585
  function convertFigures(sheetData) {
23559
23586
  let id = 1;
23560
23587
  return sheetData.figures
@@ -33412,6 +33439,7 @@
33412
33439
  "getMeasureCompiledFormula",
33413
33440
  "getPivotName",
33414
33441
  "isExistingPivot",
33442
+ "getMeasureFullDependencies",
33415
33443
  ];
33416
33444
  nextFormulaId = 1;
33417
33445
  pivots = {};
@@ -33497,7 +33525,7 @@
33497
33525
  }
33498
33526
  case "UPDATE_PIVOT": {
33499
33527
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
33500
- this.compileCalculatedMeasures(cmd.pivot.measures);
33528
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
33501
33529
  break;
33502
33530
  }
33503
33531
  }
@@ -33515,9 +33543,14 @@
33515
33543
  this.history.update("pivots", pivotId, "definition", newDefinition);
33516
33544
  }
33517
33545
  }
33518
- for (const sheetId in this.compiledMeasureFormulas) {
33519
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
33520
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
33546
+ for (const pivotId in this.compiledMeasureFormulas) {
33547
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
33548
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
33549
+ if (!measure || !measure.computedBy) {
33550
+ continue;
33551
+ }
33552
+ const sheetId = measure.computedBy.sheetId;
33553
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
33521
33554
  const newDependencies = [];
33522
33555
  for (const range of compiledFormula.dependencies) {
33523
33556
  const change = applyChange(range);
@@ -33529,8 +33562,9 @@
33529
33562
  }
33530
33563
  }
33531
33564
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
33532
- if (newFormulaString !== formulaString) {
33533
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
33565
+ const oldFormulaString = measure.computedBy.formula;
33566
+ if (newFormulaString !== oldFormulaString) {
33567
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
33534
33568
  }
33535
33569
  }
33536
33570
  }
@@ -33568,30 +33602,59 @@
33568
33602
  isExistingPivot(pivotId) {
33569
33603
  return pivotId in this.pivots;
33570
33604
  }
33571
- getMeasureCompiledFormula(measure) {
33605
+ getMeasureCompiledFormula(pivotId, measure) {
33606
+ if (!measure.computedBy) {
33607
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33608
+ }
33609
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
33610
+ }
33611
+ getMeasureFullDependencies(pivotId, measure) {
33572
33612
  if (!measure.computedBy) {
33573
33613
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33574
33614
  }
33575
- const sheetId = measure.computedBy.sheetId;
33576
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
33615
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
33577
33616
  }
33578
33617
  // -------------------------------------------------------------------------
33579
33618
  // Private
33580
33619
  // -------------------------------------------------------------------------
33581
33620
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
33582
33621
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
33583
- this.compileCalculatedMeasures(pivot.measures);
33622
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
33584
33623
  this.history.update("formulaIds", formulaId, pivotId);
33585
33624
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
33586
33625
  }
33587
- compileCalculatedMeasures(measures) {
33626
+ compileCalculatedMeasures(pivotId, measures) {
33588
33627
  for (const measure of measures) {
33589
33628
  if (measure.computedBy) {
33590
- const sheetId = measure.computedBy.sheetId;
33591
33629
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
33592
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
33630
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
33593
33631
  }
33594
33632
  }
33633
+ for (const measure of measures) {
33634
+ if (measure.computedBy) {
33635
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
33636
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
33637
+ }
33638
+ }
33639
+ }
33640
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
33641
+ const rangeDependencies = [];
33642
+ const definition = this.getPivotCoreDefinition(pivotId);
33643
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
33644
+ exploredMeasures.add(measure.id);
33645
+ for (const token of formula.tokens) {
33646
+ if (token.type !== "SYMBOL") {
33647
+ continue;
33648
+ }
33649
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
33650
+ measure.id !== measureCandidate.id);
33651
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
33652
+ continue;
33653
+ }
33654
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
33655
+ }
33656
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
33657
+ return rangeDependencies;
33595
33658
  }
33596
33659
  insertPivot(position, formulaId, table) {
33597
33660
  this.resizeSheet(position.sheetId, position, table);
@@ -33651,21 +33714,17 @@
33651
33714
  dependencies: rangeDependencies,
33652
33715
  };
33653
33716
  }
33654
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
33655
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
33656
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
33657
- for (const pivotId in this.pivots) {
33658
- const pivot = this.pivots[pivotId];
33659
- if (!pivot) {
33660
- continue;
33661
- }
33662
- for (const measure of pivot.definition.measures) {
33663
- if (measure.computedBy?.formula === formulaString) {
33664
- const measureIndex = pivot.definition.measures.indexOf(measure);
33665
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
33666
- }
33667
- }
33717
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
33718
+ const pivot = this.pivots[pivotId];
33719
+ if (!pivot) {
33720
+ return;
33668
33721
  }
33722
+ const measureIndex = pivot.definition.measures.indexOf(measure);
33723
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
33724
+ formula: newFormulaString,
33725
+ sheetId: measure.computedBy.sheetId,
33726
+ });
33727
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
33669
33728
  }
33670
33729
  checkSortedColumnInMeasures(definition) {
33671
33730
  const measures = definition.measures.map((measure) => measure.id);
@@ -34726,7 +34785,7 @@
34726
34785
  case "UPDATE_CELL":
34727
34786
  if (cmd.style !== undefined) {
34728
34787
  if (cmd.style !== null) {
34729
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
34788
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
34730
34789
  }
34731
34790
  else {
34732
34791
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -34794,16 +34853,22 @@
34794
34853
  }
34795
34854
  }
34796
34855
  styleIsDefault(style) {
34797
- return deepEquals(this.removeDefaultStyleValues(style), {});
34856
+ for (const key in style) {
34857
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
34858
+ return false;
34859
+ }
34860
+ }
34861
+ return true;
34798
34862
  }
34799
34863
  removeDefaultStyleValues(style) {
34800
34864
  const cleanedStyle = { ...style };
34801
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
34802
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34865
+ for (const property in style) {
34866
+ if (cleanedStyle[property] === undefined ||
34867
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34803
34868
  delete cleanedStyle[property];
34804
34869
  }
34805
34870
  }
34806
- return cleanedStyle;
34871
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
34807
34872
  }
34808
34873
  onMerge(sheetId, zone) {
34809
34874
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -34839,13 +34904,13 @@
34839
34904
  }
34840
34905
  editingZone = recomputeZones(editingZone, [inter]);
34841
34906
  }
34907
+ style = this.removeDefaultStyleValues(style);
34842
34908
  if (style) {
34843
- const newStyle = this.removeDefaultStyleValues(style);
34844
34909
  styles.push(...editingZone.map((zone) => {
34845
- return { zone, style: newStyle };
34910
+ return { zone, style };
34846
34911
  }));
34847
34912
  }
34848
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
34913
+ this.history.update("styles", sheetId, styles);
34849
34914
  }
34850
34915
  clearStyle(sheetId, zones) {
34851
34916
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -40487,14 +40552,16 @@
40487
40552
  function withPivotPresentationLayer (PivotClass) {
40488
40553
  class PivotPresentationLayer extends PivotClass {
40489
40554
  getters;
40555
+ pivotId;
40490
40556
  cache = {};
40491
40557
  rankAsc = {};
40492
40558
  rankDesc = {};
40493
40559
  runningTotal = {};
40494
40560
  runningTotalInPercent = {};
40495
- constructor(custom, params) {
40561
+ constructor(pivotId, custom, params) {
40496
40562
  super(custom, params);
40497
40563
  this.getters = params.getters;
40564
+ this.pivotId = pivotId;
40498
40565
  }
40499
40566
  markAsDirtyForEvaluation() {
40500
40567
  this.cache = {};
@@ -40544,7 +40611,7 @@
40544
40611
  return handleError(error, measure.aggregator.toUpperCase());
40545
40612
  }
40546
40613
  }
40547
- const formula = this.getters.getMeasureCompiledFormula(measure);
40614
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
40548
40615
  const getSymbolValue = (symbolName) => {
40549
40616
  const { columns, rows } = this.definition;
40550
40617
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -41291,7 +41358,7 @@
41291
41358
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
41292
41359
  if (!(pivotId in this.pivots)) {
41293
41360
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
41294
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
41361
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
41295
41362
  }
41296
41363
  else if (recreate) {
41297
41364
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -50283,6 +50350,9 @@
50283
50350
  if (style.alignment && style.alignment.wrapText) {
50284
50351
  alignAttrs.push(["wrapText", "1"]);
50285
50352
  }
50353
+ if (style.alignment && style.alignment.textRotation) {
50354
+ alignAttrs.push(["textRotation", style.alignment.textRotation]);
50355
+ }
50286
50356
  if (alignAttrs.length > 0) {
50287
50357
  attributes.push(["applyAlignment", "1"]); // for Libre Office
50288
50358
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
@@ -51672,8 +51742,8 @@
51672
51742
 
51673
51743
 
51674
51744
  __info__.version = "19.1.0-alpha.3";
51675
- __info__.date = "2026-01-07T16:20:59.139Z";
51676
- __info__.hash = "febc3e9";
51745
+ __info__.date = "2026-01-14T10:01:54.190Z";
51746
+ __info__.hash = "52a3e52";
51677
51747
 
51678
51748
 
51679
51749
  })(this.o_spreadsheet_engine = this.o_spreadsheet_engine || {});