@odoo/o-spreadsheet 19.1.1 → 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 2025-12-26T10:26:09.971Z
7
- * @hash e6313bd
6
+ * @date 2026-01-14T10:01:54.190Z
7
+ * @hash 52a3e52
8
8
  */
9
9
 
10
10
  class FunctionCodeBuilder {
@@ -15073,9 +15073,10 @@ function assertDomainLength(domain) {
15073
15073
  throw new EvaluationError(_t("Function PIVOT takes an even number of arguments."));
15074
15074
  }
15075
15075
  }
15076
- function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15076
+ function addPivotDependencies(evalContext, pivotId, forMeasures) {
15077
15077
  //TODO This function can be very costly when used with PIVOT.VALUE and PIVOT.HEADER
15078
15078
  const dependencies = [];
15079
+ const coreDefinition = evalContext.getters.getPivotCoreDefinition(pivotId);
15079
15080
  if (coreDefinition.type === "SPREADSHEET" && coreDefinition.dataSet) {
15080
15081
  const { sheetId, zone } = coreDefinition.dataSet;
15081
15082
  const xc = zoneToXc(zone);
@@ -15092,8 +15093,7 @@ function addPivotDependencies(evalContext, coreDefinition, forMeasures) {
15092
15093
  }
15093
15094
  for (const measure of forMeasures) {
15094
15095
  if (measure.computedBy) {
15095
- const formula = evalContext.getters.getMeasureCompiledFormula(measure);
15096
- dependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
15096
+ dependencies.push(...evalContext.getters.getMeasureFullDependencies(pivotId, measure));
15097
15097
  }
15098
15098
  }
15099
15099
  const originPosition = evalContext.__originCellPosition;
@@ -15590,7 +15590,7 @@ const PIVOT_VALUE = {
15590
15590
  assertDomainLength(domainArgs);
15591
15591
  const pivot = this.getters.getPivot(pivotId);
15592
15592
  const coreDefinition = this.getters.getPivotCoreDefinition(pivotId);
15593
- addPivotDependencies(this, coreDefinition, coreDefinition.measures.filter((m) => m.id === _measure));
15593
+ addPivotDependencies(this, pivotId, coreDefinition.measures.filter((m) => m.id === _measure));
15594
15594
  pivot.init({ reload: pivot.needsReevaluation });
15595
15595
  const error = pivot.assertIsValid({ throwOnError: false });
15596
15596
  if (error) {
@@ -15623,8 +15623,7 @@ const PIVOT_HEADER = {
15623
15623
  const _pivotId = getPivotId(_pivotFormulaId, this.getters);
15624
15624
  assertDomainLength(domainArgs);
15625
15625
  const pivot = this.getters.getPivot(_pivotId);
15626
- const coreDefinition = this.getters.getPivotCoreDefinition(_pivotId);
15627
- addPivotDependencies(this, coreDefinition, []);
15626
+ addPivotDependencies(this, _pivotId, []);
15628
15627
  pivot.init({ reload: pivot.needsReevaluation });
15629
15628
  const error = pivot.assertIsValid({ throwOnError: false });
15630
15629
  if (error) {
@@ -15676,7 +15675,7 @@ const PIVOT = {
15676
15675
  if (pivotStyle.numberOfColumns < 0) {
15677
15676
  return new EvaluationError(_t("The number of columns must be positive."));
15678
15677
  }
15679
- addPivotDependencies(this, coreDefinition, coreDefinition.measures);
15678
+ addPivotDependencies(this, pivotId, coreDefinition.measures);
15680
15679
  pivot.init({ reload: pivot.needsReevaluation });
15681
15680
  const error = pivot.assertIsValid({ throwOnError: false });
15682
15681
  if (error) {
@@ -18112,7 +18111,7 @@ class ReadonlyTransportFilter {
18112
18111
  if (message.type === "CLIENT_JOINED" ||
18113
18112
  message.type === "CLIENT_LEFT" ||
18114
18113
  message.type === "CLIENT_MOVED") {
18115
- this.transportService.sendMessage(message);
18114
+ await this.transportService.sendMessage(message);
18116
18115
  }
18117
18116
  // ignore all other messages
18118
18117
  }
@@ -20731,7 +20730,7 @@ class Session extends EventBus {
20731
20730
  }
20732
20731
  delete this.clients[this.clientId];
20733
20732
  this.transportService.leave(this.clientId);
20734
- this.transportService.sendMessage({
20733
+ this.sendToTransport({
20735
20734
  type: "CLIENT_LEFT",
20736
20735
  clientId: this.clientId,
20737
20736
  version: MESSAGE_VERSION,
@@ -20745,7 +20744,7 @@ class Session extends EventBus {
20745
20744
  return;
20746
20745
  }
20747
20746
  const snapshotId = this.uuidGenerator.uuidv4();
20748
- await this.transportService.sendMessage({
20747
+ await this.sendToTransport({
20749
20748
  type: "SNAPSHOT",
20750
20749
  nextRevisionId: snapshotId,
20751
20750
  serverRevisionId: this.serverRevisionId,
@@ -20793,10 +20792,14 @@ class Session extends EventBus {
20793
20792
  const type = currentPosition ? "CLIENT_MOVED" : "CLIENT_JOINED";
20794
20793
  const client = this.getCurrentClient();
20795
20794
  this.clients[this.clientId] = { ...client, position };
20796
- this.transportService.sendMessage({
20795
+ this.sendToTransport({
20797
20796
  type,
20798
20797
  version: MESSAGE_VERSION,
20799
20798
  client: { ...client, position },
20799
+ }).then(() => {
20800
+ if (this.pendingMessages.length > 0 && !this.waitingAck) {
20801
+ this.sendPendingMessage();
20802
+ }
20800
20803
  });
20801
20804
  }
20802
20805
  /**
@@ -20877,7 +20880,7 @@ class Session extends EventBus {
20877
20880
  if (client) {
20878
20881
  const { position } = client;
20879
20882
  if (position) {
20880
- this.transportService.sendMessage({
20883
+ this.sendToTransport({
20881
20884
  type: "CLIENT_MOVED",
20882
20885
  version: MESSAGE_VERSION,
20883
20886
  client: { ...client, position },
@@ -20898,6 +20901,10 @@ class Session extends EventBus {
20898
20901
  }
20899
20902
  this.sendPendingMessage();
20900
20903
  }
20904
+ async sendToTransport(message) {
20905
+ // wrap in an async function to ensure it returns a promise
20906
+ return this.transportService.sendMessage(message);
20907
+ }
20901
20908
  /**
20902
20909
  * Send the next pending message
20903
20910
  */
@@ -20926,9 +20933,14 @@ class Session extends EventBus {
20926
20933
  ${JSON.stringify(message)}`);
20927
20934
  }
20928
20935
  this.waitingAck = true;
20929
- this.transportService.sendMessage({
20936
+ this.sendToTransport({
20930
20937
  ...message,
20931
20938
  serverRevisionId: this.serverRevisionId,
20939
+ }).catch((e) => {
20940
+ if (!(e instanceof ClientDisconnectedError)) {
20941
+ throw e.cause || e;
20942
+ }
20943
+ this.waitingAck = false;
20932
20944
  });
20933
20945
  }
20934
20946
  acknowledge(message) {
@@ -22769,6 +22781,403 @@ function hexaToInt(hex) {
22769
22781
  */
22770
22782
  const DEFAULT_SYSTEM_COLOR = "FF000000";
22771
22783
 
22784
+ const globalReverseLookup$1 = new WeakMap();
22785
+ const globalIdCounter = new WeakMap();
22786
+ /**
22787
+ * Get the id of the given item (its key in the given dictionary).
22788
+ * If the given item does not exist in the dictionary, it creates one with a new id.
22789
+ */
22790
+ function getItemId(item, itemsDic) {
22791
+ if (!globalReverseLookup$1.has(itemsDic)) {
22792
+ globalReverseLookup$1.set(itemsDic, new Map());
22793
+ globalIdCounter.set(itemsDic, 0);
22794
+ }
22795
+ const reverseLookup = globalReverseLookup$1.get(itemsDic);
22796
+ const canonical = getCanonicalRepresentation(item);
22797
+ if (reverseLookup.has(canonical)) {
22798
+ const id = reverseLookup.get(canonical);
22799
+ itemsDic[id] = item;
22800
+ return id;
22801
+ }
22802
+ // Generate new Id if the item didn't exist in the dictionary
22803
+ const newId = globalIdCounter.get(itemsDic) + 1;
22804
+ reverseLookup.set(canonical, newId);
22805
+ globalIdCounter.set(itemsDic, newId);
22806
+ itemsDic[newId] = item;
22807
+ return newId;
22808
+ }
22809
+ function groupItemIdsByZones(positionsByItemId) {
22810
+ const result = {};
22811
+ for (const itemId in positionsByItemId) {
22812
+ const zones = recomputeZones(positionsByItemId[itemId].map(positionToZone));
22813
+ for (const zone of zones) {
22814
+ result[zoneToXc(zone)] = Number(itemId);
22815
+ }
22816
+ }
22817
+ return result;
22818
+ }
22819
+ function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
22820
+ for (const zoneXc in itemIdsByZones) {
22821
+ const zone = toZone(zoneXc);
22822
+ const itemId = itemIdsByZones[zoneXc];
22823
+ for (let row = zone.top; row <= zone.bottom; row++) {
22824
+ for (let col = zone.left; col <= zone.right; col++) {
22825
+ const position = { sheetId, col, row };
22826
+ yield [position, itemId];
22827
+ }
22828
+ }
22829
+ }
22830
+ }
22831
+ function getCanonicalRepresentation(item) {
22832
+ if (item === null)
22833
+ return "null";
22834
+ if (item === undefined)
22835
+ return "undefined";
22836
+ if (typeof item !== "object")
22837
+ return String(item);
22838
+ if (Array.isArray(item)) {
22839
+ const len = item.length;
22840
+ let result = "[";
22841
+ for (let i = 0; i < len; i++) {
22842
+ if (i > 0)
22843
+ result += ",";
22844
+ result += getCanonicalRepresentation(item[i]);
22845
+ }
22846
+ return result + "]";
22847
+ }
22848
+ const keys = Object.keys(item).sort();
22849
+ let repr = "{";
22850
+ for (const key of keys) {
22851
+ if (item[key] !== undefined) {
22852
+ repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
22853
+ }
22854
+ }
22855
+ repr += "}";
22856
+ return repr;
22857
+ }
22858
+
22859
+ // -------------------------------------
22860
+ // CF HELPERS
22861
+ // -------------------------------------
22862
+ /**
22863
+ * Convert the conditional formatting o-spreadsheet operator to
22864
+ * the corresponding excel operator.
22865
+ * */
22866
+ function convertOperator(operator) {
22867
+ switch (operator) {
22868
+ case "isNotEmpty":
22869
+ return "notContainsBlanks";
22870
+ case "isEmpty":
22871
+ return "containsBlanks";
22872
+ case "notContainsText":
22873
+ return "notContainsBlanks";
22874
+ case "containsText":
22875
+ return "containsText";
22876
+ case "beginsWithText":
22877
+ return "beginsWith";
22878
+ case "endsWithText":
22879
+ return "endsWith";
22880
+ case "isGreaterThan":
22881
+ return "greaterThan";
22882
+ case "isGreaterOrEqualTo":
22883
+ return "greaterThanOrEqual";
22884
+ case "isLessThan":
22885
+ return "lessThan";
22886
+ case "isLessOrEqualTo":
22887
+ return "lessThanOrEqual";
22888
+ case "isBetween":
22889
+ return "between";
22890
+ case "isNotBetween":
22891
+ return "notBetween";
22892
+ case "isEqual":
22893
+ return "equal";
22894
+ case "isNotEqual":
22895
+ return "notEqual";
22896
+ case "customFormula":
22897
+ return "";
22898
+ case "dateIs":
22899
+ return "";
22900
+ case "dateIsBefore":
22901
+ return "lessThan";
22902
+ case "dateIsAfter":
22903
+ return "greaterThan";
22904
+ case "dateIsOnOrAfter":
22905
+ return "greaterThanOrEqual";
22906
+ case "dateIsOnOrBefore":
22907
+ return "lessThanOrEqual";
22908
+ }
22909
+ }
22910
+ // -------------------------------------
22911
+ // WORKSHEET HELPERS
22912
+ // -------------------------------------
22913
+ function getCellType(value) {
22914
+ switch (typeof value) {
22915
+ case "boolean":
22916
+ return "b";
22917
+ case "string":
22918
+ return "str";
22919
+ case "number":
22920
+ return "n";
22921
+ default:
22922
+ return undefined;
22923
+ }
22924
+ }
22925
+ function convertHeightToExcel(height) {
22926
+ return Math.round(HEIGHT_FACTOR * height * 100) / 100;
22927
+ }
22928
+ function convertWidthToExcel(width) {
22929
+ return Math.round(WIDTH_FACTOR * width * 100) / 100;
22930
+ }
22931
+ function convertHeightFromExcel(height) {
22932
+ if (!height)
22933
+ return height;
22934
+ return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
22935
+ }
22936
+ function convertWidthFromExcel(width) {
22937
+ if (!width)
22938
+ return width;
22939
+ return Math.round((width / WIDTH_FACTOR) * 100) / 100;
22940
+ }
22941
+ function extractStyle(data, content, styleId, formatId, borderId) {
22942
+ const style = styleId ? data.styles[styleId] : {};
22943
+ const format = formatId ? data.formats[formatId] : undefined;
22944
+ const styles = {
22945
+ font: {
22946
+ size: style?.fontSize || DEFAULT_FONT_SIZE,
22947
+ color: { rgb: style?.textColor ? style.textColor : "000000" },
22948
+ family: 2,
22949
+ name: "Arial",
22950
+ },
22951
+ fill: style?.fillColor
22952
+ ? {
22953
+ fgColor: { rgb: style.fillColor },
22954
+ }
22955
+ : { reservedAttribute: "none" },
22956
+ numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
22957
+ border: borderId || 0,
22958
+ alignment: {
22959
+ horizontal: style.align,
22960
+ vertical: style.verticalAlign
22961
+ ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
22962
+ : undefined,
22963
+ wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
22964
+ textRotation: style.rotation ? rotationToXLSX(style.rotation) : undefined,
22965
+ },
22966
+ };
22967
+ styles.font["strike"] = !!style?.strikethrough || undefined;
22968
+ styles.font["underline"] = !!style?.underline || undefined;
22969
+ styles.font["bold"] = !!style?.bold || undefined;
22970
+ styles.font["italic"] = !!style?.italic || undefined;
22971
+ return styles;
22972
+ }
22973
+ function rotationToXLSX(rad) {
22974
+ let deg = Math.round((-rad / Math.PI) * 180) % 180;
22975
+ if (deg > 90) {
22976
+ deg -= 180;
22977
+ }
22978
+ else if (deg < -90) {
22979
+ deg += 180;
22980
+ }
22981
+ if (deg >= 0) {
22982
+ return deg;
22983
+ }
22984
+ else {
22985
+ return 90 - deg;
22986
+ }
22987
+ }
22988
+ function rotationFromXLSX(deg) {
22989
+ if (deg <= 90) {
22990
+ return -(deg / 180) * Math.PI;
22991
+ }
22992
+ else {
22993
+ return (-(90 - deg) / 180) * Math.PI;
22994
+ }
22995
+ }
22996
+ function normalizeStyle(construct, styles) {
22997
+ // Normalize this
22998
+ const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
22999
+ const style = {
23000
+ fontId: pushElement(styles.font, construct.fonts),
23001
+ fillId: pushElement(styles.fill, construct.fills),
23002
+ borderId: styles.border,
23003
+ numFmtId,
23004
+ alignment: {
23005
+ vertical: styles.alignment.vertical,
23006
+ horizontal: styles.alignment.horizontal,
23007
+ wrapText: styles.alignment.wrapText,
23008
+ textRotation: styles.alignment.textRotation,
23009
+ },
23010
+ };
23011
+ return pushElement(style, construct.styles);
23012
+ }
23013
+ function convertFormat(format, numFmtStructure) {
23014
+ if (!format) {
23015
+ return 0;
23016
+ }
23017
+ let formatId = XLSX_FORMAT_MAP[format.format];
23018
+ if (!formatId) {
23019
+ formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
23020
+ }
23021
+ return formatId;
23022
+ }
23023
+ /**
23024
+ * Add a relation to the given file and return its id.
23025
+ */
23026
+ function addRelsToFile(relsFiles, path, rel) {
23027
+ const relsFile = relsFiles.find((file) => file.path === path);
23028
+ // the id is a one-based int casted as string
23029
+ let id;
23030
+ if (!relsFile) {
23031
+ id = "rId1";
23032
+ relsFiles.push({ path, rels: [{ ...rel, id }] });
23033
+ }
23034
+ else {
23035
+ id = `rId${(relsFile.rels.length + 1).toString()}`;
23036
+ relsFile.rels.push({
23037
+ ...rel,
23038
+ id,
23039
+ });
23040
+ }
23041
+ return id;
23042
+ }
23043
+ const globalReverseLookup = new WeakMap();
23044
+ function pushElement(property, propertyList) {
23045
+ let reverseLookup = globalReverseLookup.get(propertyList);
23046
+ if (!reverseLookup) {
23047
+ reverseLookup = new Map();
23048
+ for (let i = 0; i < propertyList.length; i++) {
23049
+ const canonical = getCanonicalRepresentation(propertyList[i]);
23050
+ reverseLookup.set(canonical, i);
23051
+ }
23052
+ globalReverseLookup.set(propertyList, reverseLookup);
23053
+ }
23054
+ const canonical = getCanonicalRepresentation(property);
23055
+ if (reverseLookup.has(canonical)) {
23056
+ return reverseLookup.get(canonical);
23057
+ }
23058
+ const maxId = propertyList.length;
23059
+ propertyList.push(property);
23060
+ reverseLookup.set(canonical, maxId);
23061
+ return maxId;
23062
+ }
23063
+ /**
23064
+ * Convert a chart o-spreadsheet id to a xlsx id which
23065
+ * are unsigned integers (starting from 1).
23066
+ */
23067
+ function convertChartId(chartId, construct) {
23068
+ const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
23069
+ if (xlsxId === -1) {
23070
+ construct.chartIds.push(chartId);
23071
+ return construct.chartIds.length;
23072
+ }
23073
+ return xlsxId + 1;
23074
+ }
23075
+ const imageIds = [];
23076
+ /**
23077
+ * Convert a image o-spreadsheet id to a xlsx id which
23078
+ * are unsigned integers (starting from 1).
23079
+ */
23080
+ function convertImageId(imageId) {
23081
+ const xlsxId = imageIds.findIndex((id) => id === imageId);
23082
+ if (xlsxId === -1) {
23083
+ imageIds.push(imageId);
23084
+ return imageIds.length;
23085
+ }
23086
+ return xlsxId + 1;
23087
+ }
23088
+ /**
23089
+ * Convert a value expressed in dot to EMU.
23090
+ * EMU = English Metrical Unit
23091
+ * There are 914400 EMU per inch.
23092
+ *
23093
+ * /!\ A value expressed in EMU cannot be fractional.
23094
+ * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
23095
+ */
23096
+ function convertDotValueToEMU(value) {
23097
+ const DPI = 96;
23098
+ return Math.round((value * 914400) / DPI);
23099
+ }
23100
+ function getRangeSize(reference, defaultSheetIndex, data) {
23101
+ let xc = reference;
23102
+ let sheetName = undefined;
23103
+ ({ xc, sheetName } = splitReference(reference));
23104
+ let rangeSheetIndex;
23105
+ if (sheetName) {
23106
+ const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
23107
+ if (index < 0) {
23108
+ throw new Error("Unable to find a sheet with the name " + sheetName);
23109
+ }
23110
+ rangeSheetIndex = index;
23111
+ }
23112
+ else {
23113
+ rangeSheetIndex = Number(defaultSheetIndex);
23114
+ }
23115
+ const zone = toUnboundedZone(xc);
23116
+ if (zone.right === undefined) {
23117
+ zone.right = data.sheets[rangeSheetIndex].colNumber;
23118
+ }
23119
+ if (zone.bottom === undefined) {
23120
+ zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
23121
+ }
23122
+ return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
23123
+ }
23124
+ function convertEMUToDotValue(value) {
23125
+ const DPI = 96;
23126
+ return Math.round((value * DPI) / 914400);
23127
+ }
23128
+ /**
23129
+ * Get the position of the start of a column in Excel (in px).
23130
+ */
23131
+ function getColPosition(colIndex, sheetData) {
23132
+ let position = 0;
23133
+ for (let i = 0; i < colIndex; i++) {
23134
+ const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
23135
+ if (colAtIndex?.width) {
23136
+ position += colAtIndex.width;
23137
+ }
23138
+ else if (sheetData.sheetFormat?.defaultColWidth) {
23139
+ position += sheetData.sheetFormat.defaultColWidth;
23140
+ }
23141
+ else {
23142
+ position += EXCEL_DEFAULT_COL_WIDTH;
23143
+ }
23144
+ }
23145
+ return position / WIDTH_FACTOR;
23146
+ }
23147
+ /**
23148
+ * Get the position of the start of a row in Excel (in px).
23149
+ */
23150
+ function getRowPosition(rowIndex, sheetData) {
23151
+ let position = 0;
23152
+ for (let i = 0; i < rowIndex; i++) {
23153
+ const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
23154
+ if (rowAtIndex?.height) {
23155
+ position += rowAtIndex.height;
23156
+ }
23157
+ else if (sheetData.sheetFormat?.defaultRowHeight) {
23158
+ position += sheetData.sheetFormat.defaultRowHeight;
23159
+ }
23160
+ else {
23161
+ position += EXCEL_DEFAULT_ROW_HEIGHT;
23162
+ }
23163
+ }
23164
+ return position / HEIGHT_FACTOR;
23165
+ }
23166
+ /**
23167
+ * Convert the o-spreadsheet data validation decimal
23168
+ * criterion type to the corresponding excel operator.
23169
+ */
23170
+ function convertDecimalCriterionTypeToExcelOperator(operator) {
23171
+ return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
23172
+ }
23173
+ /**
23174
+ * Convert the o-spreadsheet data validation date
23175
+ * criterion type to the corresponding excel operator.
23176
+ */
23177
+ function convertDateCriterionTypeToExcelOperator(operator) {
23178
+ return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
23179
+ }
23180
+
22772
23181
  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;
22773
23182
  /**
22774
23183
  * Convert excel format to o_spreadsheet format
@@ -22868,6 +23277,9 @@ function convertStyle(styleStruct, warningManager) {
22868
23277
  align: styleStruct.alignment?.horizontal
22869
23278
  ? H_ALIGNMENT_CONVERSION_MAP[styleStruct.alignment.horizontal]
22870
23279
  : undefined,
23280
+ rotation: styleStruct.alignment?.textRotation
23281
+ ? rotationFromXLSX(styleStruct.alignment.textRotation)
23282
+ : undefined,
22871
23283
  // 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
22872
23284
  fillColor: styleStruct.fillStyle?.patternType === "solid"
22873
23285
  ? convertColor(styleStruct.fillStyle?.fgColor)
@@ -23167,378 +23579,6 @@ function addCfConversionWarnings(cf, dxfs, warningManager) {
23167
23579
  }
23168
23580
  }
23169
23581
 
23170
- const globalReverseLookup$1 = new WeakMap();
23171
- const globalIdCounter = new WeakMap();
23172
- /**
23173
- * Get the id of the given item (its key in the given dictionary).
23174
- * If the given item does not exist in the dictionary, it creates one with a new id.
23175
- */
23176
- function getItemId(item, itemsDic) {
23177
- if (!globalReverseLookup$1.has(itemsDic)) {
23178
- globalReverseLookup$1.set(itemsDic, new Map());
23179
- globalIdCounter.set(itemsDic, 0);
23180
- }
23181
- const reverseLookup = globalReverseLookup$1.get(itemsDic);
23182
- const canonical = getCanonicalRepresentation(item);
23183
- if (reverseLookup.has(canonical)) {
23184
- const id = reverseLookup.get(canonical);
23185
- itemsDic[id] = item;
23186
- return id;
23187
- }
23188
- // Generate new Id if the item didn't exist in the dictionary
23189
- const newId = globalIdCounter.get(itemsDic) + 1;
23190
- reverseLookup.set(canonical, newId);
23191
- globalIdCounter.set(itemsDic, newId);
23192
- itemsDic[newId] = item;
23193
- return newId;
23194
- }
23195
- function groupItemIdsByZones(positionsByItemId) {
23196
- const result = {};
23197
- for (const itemId in positionsByItemId) {
23198
- const zones = recomputeZones(positionsByItemId[itemId].map(positionToZone));
23199
- for (const zone of zones) {
23200
- result[zoneToXc(zone)] = Number(itemId);
23201
- }
23202
- }
23203
- return result;
23204
- }
23205
- function* iterateItemIdsPositions(sheetId, itemIdsByZones) {
23206
- for (const zoneXc in itemIdsByZones) {
23207
- const zone = toZone(zoneXc);
23208
- const itemId = itemIdsByZones[zoneXc];
23209
- for (let row = zone.top; row <= zone.bottom; row++) {
23210
- for (let col = zone.left; col <= zone.right; col++) {
23211
- const position = { sheetId, col, row };
23212
- yield [position, itemId];
23213
- }
23214
- }
23215
- }
23216
- }
23217
- function getCanonicalRepresentation(item) {
23218
- if (item === null)
23219
- return "null";
23220
- if (item === undefined)
23221
- return "undefined";
23222
- if (typeof item !== "object")
23223
- return String(item);
23224
- if (Array.isArray(item)) {
23225
- const len = item.length;
23226
- let result = "[";
23227
- for (let i = 0; i < len; i++) {
23228
- if (i > 0)
23229
- result += ",";
23230
- result += getCanonicalRepresentation(item[i]);
23231
- }
23232
- return result + "]";
23233
- }
23234
- const keys = Object.keys(item).sort();
23235
- let repr = "{";
23236
- for (const key of keys) {
23237
- if (item[key] !== undefined) {
23238
- repr += `"${key}":${getCanonicalRepresentation(item[key])},`;
23239
- }
23240
- }
23241
- repr += "}";
23242
- return repr;
23243
- }
23244
-
23245
- // -------------------------------------
23246
- // CF HELPERS
23247
- // -------------------------------------
23248
- /**
23249
- * Convert the conditional formatting o-spreadsheet operator to
23250
- * the corresponding excel operator.
23251
- * */
23252
- function convertOperator(operator) {
23253
- switch (operator) {
23254
- case "isNotEmpty":
23255
- return "notContainsBlanks";
23256
- case "isEmpty":
23257
- return "containsBlanks";
23258
- case "notContainsText":
23259
- return "notContainsBlanks";
23260
- case "containsText":
23261
- return "containsText";
23262
- case "beginsWithText":
23263
- return "beginsWith";
23264
- case "endsWithText":
23265
- return "endsWith";
23266
- case "isGreaterThan":
23267
- return "greaterThan";
23268
- case "isGreaterOrEqualTo":
23269
- return "greaterThanOrEqual";
23270
- case "isLessThan":
23271
- return "lessThan";
23272
- case "isLessOrEqualTo":
23273
- return "lessThanOrEqual";
23274
- case "isBetween":
23275
- return "between";
23276
- case "isNotBetween":
23277
- return "notBetween";
23278
- case "isEqual":
23279
- return "equal";
23280
- case "isNotEqual":
23281
- return "notEqual";
23282
- case "customFormula":
23283
- return "";
23284
- case "dateIs":
23285
- return "";
23286
- case "dateIsBefore":
23287
- return "lessThan";
23288
- case "dateIsAfter":
23289
- return "greaterThan";
23290
- case "dateIsOnOrAfter":
23291
- return "greaterThanOrEqual";
23292
- case "dateIsOnOrBefore":
23293
- return "lessThanOrEqual";
23294
- }
23295
- }
23296
- // -------------------------------------
23297
- // WORKSHEET HELPERS
23298
- // -------------------------------------
23299
- function getCellType(value) {
23300
- switch (typeof value) {
23301
- case "boolean":
23302
- return "b";
23303
- case "string":
23304
- return "str";
23305
- case "number":
23306
- return "n";
23307
- default:
23308
- return undefined;
23309
- }
23310
- }
23311
- function convertHeightToExcel(height) {
23312
- return Math.round(HEIGHT_FACTOR * height * 100) / 100;
23313
- }
23314
- function convertWidthToExcel(width) {
23315
- return Math.round(WIDTH_FACTOR * width * 100) / 100;
23316
- }
23317
- function convertHeightFromExcel(height) {
23318
- if (!height)
23319
- return height;
23320
- return Math.round((height / HEIGHT_FACTOR) * 100) / 100;
23321
- }
23322
- function convertWidthFromExcel(width) {
23323
- if (!width)
23324
- return width;
23325
- return Math.round((width / WIDTH_FACTOR) * 100) / 100;
23326
- }
23327
- function extractStyle(data, content, styleId, formatId, borderId) {
23328
- const style = styleId ? data.styles[styleId] : {};
23329
- const format = formatId ? data.formats[formatId] : undefined;
23330
- const styles = {
23331
- font: {
23332
- size: style?.fontSize || DEFAULT_FONT_SIZE,
23333
- color: { rgb: style?.textColor ? style.textColor : "000000" },
23334
- family: 2,
23335
- name: "Arial",
23336
- },
23337
- fill: style?.fillColor
23338
- ? {
23339
- fgColor: { rgb: style.fillColor },
23340
- }
23341
- : { reservedAttribute: "none" },
23342
- numFmt: format ? { format: format, id: 0 /* id not used for export */ } : undefined,
23343
- border: borderId || 0,
23344
- alignment: {
23345
- horizontal: style.align,
23346
- vertical: style.verticalAlign
23347
- ? V_ALIGNMENT_EXPORT_CONVERSION_MAP[style.verticalAlign]
23348
- : undefined,
23349
- wrapText: style.wrapping === "wrap" || content?.includes(NEWLINE) ? true : undefined,
23350
- },
23351
- };
23352
- styles.font["strike"] = !!style?.strikethrough || undefined;
23353
- styles.font["underline"] = !!style?.underline || undefined;
23354
- styles.font["bold"] = !!style?.bold || undefined;
23355
- styles.font["italic"] = !!style?.italic || undefined;
23356
- return styles;
23357
- }
23358
- function normalizeStyle(construct, styles) {
23359
- // Normalize this
23360
- const numFmtId = convertFormat(styles["numFmt"], construct.numFmts);
23361
- const style = {
23362
- fontId: pushElement(styles.font, construct.fonts),
23363
- fillId: pushElement(styles.fill, construct.fills),
23364
- borderId: styles.border,
23365
- numFmtId,
23366
- alignment: {
23367
- vertical: styles.alignment.vertical,
23368
- horizontal: styles.alignment.horizontal,
23369
- wrapText: styles.alignment.wrapText,
23370
- },
23371
- };
23372
- return pushElement(style, construct.styles);
23373
- }
23374
- function convertFormat(format, numFmtStructure) {
23375
- if (!format) {
23376
- return 0;
23377
- }
23378
- let formatId = XLSX_FORMAT_MAP[format.format];
23379
- if (!formatId) {
23380
- formatId = pushElement(format, numFmtStructure) + FIRST_NUMFMT_ID;
23381
- }
23382
- return formatId;
23383
- }
23384
- /**
23385
- * Add a relation to the given file and return its id.
23386
- */
23387
- function addRelsToFile(relsFiles, path, rel) {
23388
- const relsFile = relsFiles.find((file) => file.path === path);
23389
- // the id is a one-based int casted as string
23390
- let id;
23391
- if (!relsFile) {
23392
- id = "rId1";
23393
- relsFiles.push({ path, rels: [{ ...rel, id }] });
23394
- }
23395
- else {
23396
- id = `rId${(relsFile.rels.length + 1).toString()}`;
23397
- relsFile.rels.push({
23398
- ...rel,
23399
- id,
23400
- });
23401
- }
23402
- return id;
23403
- }
23404
- const globalReverseLookup = new WeakMap();
23405
- function pushElement(property, propertyList) {
23406
- let reverseLookup = globalReverseLookup.get(propertyList);
23407
- if (!reverseLookup) {
23408
- reverseLookup = new Map();
23409
- for (let i = 0; i < propertyList.length; i++) {
23410
- const canonical = getCanonicalRepresentation(propertyList[i]);
23411
- reverseLookup.set(canonical, i);
23412
- }
23413
- globalReverseLookup.set(propertyList, reverseLookup);
23414
- }
23415
- const canonical = getCanonicalRepresentation(property);
23416
- if (reverseLookup.has(canonical)) {
23417
- return reverseLookup.get(canonical);
23418
- }
23419
- const maxId = propertyList.length;
23420
- propertyList.push(property);
23421
- reverseLookup.set(canonical, maxId);
23422
- return maxId;
23423
- }
23424
- /**
23425
- * Convert a chart o-spreadsheet id to a xlsx id which
23426
- * are unsigned integers (starting from 1).
23427
- */
23428
- function convertChartId(chartId, construct) {
23429
- const xlsxId = construct.chartIds.findIndex((id) => id === chartId);
23430
- if (xlsxId === -1) {
23431
- construct.chartIds.push(chartId);
23432
- return construct.chartIds.length;
23433
- }
23434
- return xlsxId + 1;
23435
- }
23436
- const imageIds = [];
23437
- /**
23438
- * Convert a image o-spreadsheet id to a xlsx id which
23439
- * are unsigned integers (starting from 1).
23440
- */
23441
- function convertImageId(imageId) {
23442
- const xlsxId = imageIds.findIndex((id) => id === imageId);
23443
- if (xlsxId === -1) {
23444
- imageIds.push(imageId);
23445
- return imageIds.length;
23446
- }
23447
- return xlsxId + 1;
23448
- }
23449
- /**
23450
- * Convert a value expressed in dot to EMU.
23451
- * EMU = English Metrical Unit
23452
- * There are 914400 EMU per inch.
23453
- *
23454
- * /!\ A value expressed in EMU cannot be fractional.
23455
- * See https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vml-units#other-units-of-measurement
23456
- */
23457
- function convertDotValueToEMU(value) {
23458
- const DPI = 96;
23459
- return Math.round((value * 914400) / DPI);
23460
- }
23461
- function getRangeSize(reference, defaultSheetIndex, data) {
23462
- let xc = reference;
23463
- let sheetName = undefined;
23464
- ({ xc, sheetName } = splitReference(reference));
23465
- let rangeSheetIndex;
23466
- if (sheetName) {
23467
- const index = data.sheets.findIndex((sheet) => isSheetNameEqual(sheet.name, sheetName));
23468
- if (index < 0) {
23469
- throw new Error("Unable to find a sheet with the name " + sheetName);
23470
- }
23471
- rangeSheetIndex = index;
23472
- }
23473
- else {
23474
- rangeSheetIndex = Number(defaultSheetIndex);
23475
- }
23476
- const zone = toUnboundedZone(xc);
23477
- if (zone.right === undefined) {
23478
- zone.right = data.sheets[rangeSheetIndex].colNumber;
23479
- }
23480
- if (zone.bottom === undefined) {
23481
- zone.bottom = data.sheets[rangeSheetIndex].rowNumber;
23482
- }
23483
- return (zone.right - zone.left + 1) * (zone.bottom - zone.top + 1);
23484
- }
23485
- function convertEMUToDotValue(value) {
23486
- const DPI = 96;
23487
- return Math.round((value * DPI) / 914400);
23488
- }
23489
- /**
23490
- * Get the position of the start of a column in Excel (in px).
23491
- */
23492
- function getColPosition(colIndex, sheetData) {
23493
- let position = 0;
23494
- for (let i = 0; i < colIndex; i++) {
23495
- const colAtIndex = sheetData.cols.find((col) => i >= col.min && i <= col.max);
23496
- if (colAtIndex?.width) {
23497
- position += colAtIndex.width;
23498
- }
23499
- else if (sheetData.sheetFormat?.defaultColWidth) {
23500
- position += sheetData.sheetFormat.defaultColWidth;
23501
- }
23502
- else {
23503
- position += EXCEL_DEFAULT_COL_WIDTH;
23504
- }
23505
- }
23506
- return position / WIDTH_FACTOR;
23507
- }
23508
- /**
23509
- * Get the position of the start of a row in Excel (in px).
23510
- */
23511
- function getRowPosition(rowIndex, sheetData) {
23512
- let position = 0;
23513
- for (let i = 0; i < rowIndex; i++) {
23514
- const rowAtIndex = sheetData.rows.find((row) => row.index - 1 === i);
23515
- if (rowAtIndex?.height) {
23516
- position += rowAtIndex.height;
23517
- }
23518
- else if (sheetData.sheetFormat?.defaultRowHeight) {
23519
- position += sheetData.sheetFormat.defaultRowHeight;
23520
- }
23521
- else {
23522
- position += EXCEL_DEFAULT_ROW_HEIGHT;
23523
- }
23524
- }
23525
- return position / HEIGHT_FACTOR;
23526
- }
23527
- /**
23528
- * Convert the o-spreadsheet data validation decimal
23529
- * criterion type to the corresponding excel operator.
23530
- */
23531
- function convertDecimalCriterionTypeToExcelOperator(operator) {
23532
- return Object.keys(XLSX_DV_DECIMAL_OPERATOR_MAPPING).find((key) => XLSX_DV_DECIMAL_OPERATOR_MAPPING[key] === operator);
23533
- }
23534
- /**
23535
- * Convert the o-spreadsheet data validation date
23536
- * criterion type to the corresponding excel operator.
23537
- */
23538
- function convertDateCriterionTypeToExcelOperator(operator) {
23539
- return Object.keys(XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING).find((key) => XLSX_DV_DATE_OPERATOR_TO_DV_TYPE_MAPPING[key] === operator);
23540
- }
23541
-
23542
23582
  function convertFigures(sheetData) {
23543
23583
  let id = 1;
23544
23584
  return sheetData.figures
@@ -23910,17 +23950,41 @@ function toCriterionDateNumber(dateValue) {
23910
23950
  const today = DateTime.now();
23911
23951
  switch (dateValue) {
23912
23952
  case "today":
23913
- return jsDateToNumber(today);
23914
- case "yesterday":
23915
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 1)));
23916
- case "tomorrow":
23917
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() + 1)));
23953
+ return Math.floor(jsDateToNumber(today));
23954
+ case "yesterday": {
23955
+ today.setDate(today.getDate() - 1);
23956
+ return Math.floor(jsDateToNumber(today));
23957
+ }
23958
+ case "tomorrow": {
23959
+ today.setDate(today.getDate() + 1);
23960
+ return Math.floor(jsDateToNumber(today));
23961
+ }
23918
23962
  case "lastWeek":
23919
- return jsDateToNumber(DateTime.fromTimestamp(today.setDate(today.getDate() - 7)));
23920
- case "lastMonth":
23921
- return jsDateToNumber(DateTime.fromTimestamp(today.setMonth(today.getMonth() - 1)));
23963
+ today.setDate(today.getDate() - 6);
23964
+ return Math.floor(jsDateToNumber(today));
23965
+ case "lastMonth": {
23966
+ const lastMonth = today.getMonth() === 0 ? 11 : today.getMonth() - 1;
23967
+ const dateInLastMonth = new DateTime(today.getFullYear(), lastMonth, 1);
23968
+ if (today.getDate() > getDaysInMonth(dateInLastMonth)) {
23969
+ today.setDate(1);
23970
+ }
23971
+ else {
23972
+ today.setDate(today.getDate() + 1);
23973
+ today.setMonth(today.getMonth() - 1);
23974
+ }
23975
+ return Math.floor(jsDateToNumber(today));
23976
+ }
23922
23977
  case "lastYear":
23923
- return jsDateToNumber(DateTime.fromTimestamp(today.setFullYear(today.getFullYear() - 1)));
23978
+ // Handle leap year case
23979
+ if (today.getMonth() === 1 && today.getDate() === 29) {
23980
+ today.setDate(28);
23981
+ today.setFullYear(today.getFullYear() - 1);
23982
+ }
23983
+ else {
23984
+ today.setDate(today.getDate() + 1);
23985
+ today.setFullYear(today.getFullYear() - 1);
23986
+ }
23987
+ return Math.floor(jsDateToNumber(today));
23924
23988
  }
23925
23989
  }
23926
23990
  /** Get all the dates values of a criterion converted to numbers, converting date values such as "today" to actual dates */
@@ -28945,7 +29009,7 @@ criterionEvaluatorRegistry.add("dateIs", {
28945
29009
  return false;
28946
29010
  }
28947
29011
  if (["lastWeek", "lastMonth", "lastYear"].includes(criterion.dateValue)) {
28948
- const today = jsDateToRoundNumber(DateTime.now());
29012
+ const today = Math.floor(jsDateToNumber(DateTime.now()));
28949
29013
  return isDateBetween(dateValue, today, criterionValue);
28950
29014
  }
28951
29015
  return areDatesSameDay(dateValue, criterionValue);
@@ -33372,6 +33436,7 @@ class PivotCorePlugin extends CorePlugin {
33372
33436
  "getMeasureCompiledFormula",
33373
33437
  "getPivotName",
33374
33438
  "isExistingPivot",
33439
+ "getMeasureFullDependencies",
33375
33440
  ];
33376
33441
  nextFormulaId = 1;
33377
33442
  pivots = {};
@@ -33457,7 +33522,7 @@ class PivotCorePlugin extends CorePlugin {
33457
33522
  }
33458
33523
  case "UPDATE_PIVOT": {
33459
33524
  this.history.update("pivots", cmd.pivotId, "definition", deepCopy(cmd.pivot));
33460
- this.compileCalculatedMeasures(cmd.pivot.measures);
33525
+ this.compileCalculatedMeasures(cmd.pivotId, cmd.pivot.measures);
33461
33526
  break;
33462
33527
  }
33463
33528
  }
@@ -33475,9 +33540,14 @@ class PivotCorePlugin extends CorePlugin {
33475
33540
  this.history.update("pivots", pivotId, "definition", newDefinition);
33476
33541
  }
33477
33542
  }
33478
- for (const sheetId in this.compiledMeasureFormulas) {
33479
- for (const formulaString in this.compiledMeasureFormulas[sheetId]) {
33480
- const compiledFormula = this.compiledMeasureFormulas[sheetId][formulaString];
33543
+ for (const pivotId in this.compiledMeasureFormulas) {
33544
+ for (const measureId in this.compiledMeasureFormulas[pivotId]) {
33545
+ const measure = this.pivots[pivotId]?.definition.measures.find((m) => m.id === measureId);
33546
+ if (!measure || !measure.computedBy) {
33547
+ continue;
33548
+ }
33549
+ const sheetId = measure.computedBy.sheetId;
33550
+ const compiledFormula = this.compiledMeasureFormulas[pivotId][measureId].formula;
33481
33551
  const newDependencies = [];
33482
33552
  for (const range of compiledFormula.dependencies) {
33483
33553
  const change = applyChange(range);
@@ -33489,8 +33559,9 @@ class PivotCorePlugin extends CorePlugin {
33489
33559
  }
33490
33560
  }
33491
33561
  const newFormulaString = this.getters.getFormulaString(sheetId, compiledFormula.tokens, newDependencies);
33492
- if (newFormulaString !== formulaString) {
33493
- this.replaceMeasureFormula(sheetId, formulaString, newFormulaString);
33562
+ const oldFormulaString = measure.computedBy.formula;
33563
+ if (newFormulaString !== oldFormulaString) {
33564
+ this.replaceMeasureFormula(pivotId, measure, newFormulaString);
33494
33565
  }
33495
33566
  }
33496
33567
  }
@@ -33528,31 +33599,60 @@ class PivotCorePlugin extends CorePlugin {
33528
33599
  isExistingPivot(pivotId) {
33529
33600
  return pivotId in this.pivots;
33530
33601
  }
33531
- getMeasureCompiledFormula(measure) {
33602
+ getMeasureCompiledFormula(pivotId, measure) {
33603
+ if (!measure.computedBy) {
33604
+ throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33605
+ }
33606
+ return this.compiledMeasureFormulas[pivotId][measure.id].formula;
33607
+ }
33608
+ getMeasureFullDependencies(pivotId, measure) {
33532
33609
  if (!measure.computedBy) {
33533
33610
  throw new Error(`Measure ${measure.fieldName} is not computed by formula`);
33534
33611
  }
33535
- const sheetId = measure.computedBy.sheetId;
33536
- return this.compiledMeasureFormulas[sheetId][measure.computedBy.formula];
33612
+ return this.compiledMeasureFormulas[pivotId][measure.id].dependencies;
33537
33613
  }
33538
33614
  // -------------------------------------------------------------------------
33539
33615
  // Private
33540
33616
  // -------------------------------------------------------------------------
33541
33617
  addPivot(pivotId, pivot, formulaId = this.nextFormulaId.toString()) {
33542
33618
  this.history.update("pivots", pivotId, { definition: deepCopy(pivot), formulaId });
33543
- this.compileCalculatedMeasures(pivot.measures);
33619
+ this.compileCalculatedMeasures(pivotId, pivot.measures);
33544
33620
  this.history.update("formulaIds", formulaId, pivotId);
33545
33621
  this.history.update("nextFormulaId", this.nextFormulaId + 1);
33546
33622
  }
33547
- compileCalculatedMeasures(measures) {
33623
+ compileCalculatedMeasures(pivotId, measures) {
33548
33624
  for (const measure of measures) {
33549
33625
  if (measure.computedBy) {
33550
- const sheetId = measure.computedBy.sheetId;
33551
33626
  const compiledFormula = this.compileMeasureFormula(measure.computedBy.sheetId, measure.computedBy.formula);
33552
- this.history.update("compiledMeasureFormulas", sheetId, measure.computedBy.formula, compiledFormula);
33627
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "formula", compiledFormula);
33628
+ }
33629
+ }
33630
+ for (const measure of measures) {
33631
+ if (measure.computedBy) {
33632
+ const dependencies = this.computeMeasureFullDependencies(pivotId, measure);
33633
+ this.history.update("compiledMeasureFormulas", pivotId, measure.id, "dependencies", dependencies);
33553
33634
  }
33554
33635
  }
33555
33636
  }
33637
+ computeMeasureFullDependencies(pivotId, measure, exploredMeasures = new Set()) {
33638
+ const rangeDependencies = [];
33639
+ const definition = this.getPivotCoreDefinition(pivotId);
33640
+ const formula = this.getMeasureCompiledFormula(pivotId, measure);
33641
+ exploredMeasures.add(measure.id);
33642
+ for (const token of formula.tokens) {
33643
+ if (token.type !== "SYMBOL") {
33644
+ continue;
33645
+ }
33646
+ const otherMeasure = definition.measures.find((measureCandidate) => getCanonicalSymbolName(measureCandidate.id) === token.value &&
33647
+ measure.id !== measureCandidate.id);
33648
+ if (!otherMeasure || exploredMeasures.has(otherMeasure.id) || !otherMeasure.computedBy) {
33649
+ continue;
33650
+ }
33651
+ rangeDependencies.push(...this.computeMeasureFullDependencies(pivotId, otherMeasure, exploredMeasures));
33652
+ }
33653
+ rangeDependencies.push(...formula.dependencies.filter((range) => !range.invalidXc));
33654
+ return rangeDependencies;
33655
+ }
33556
33656
  insertPivot(position, formulaId, table) {
33557
33657
  this.resizeSheet(position.sheetId, position, table);
33558
33658
  const pivotCells = table.getPivotCells();
@@ -33611,21 +33711,17 @@ class PivotCorePlugin extends CorePlugin {
33611
33711
  dependencies: rangeDependencies,
33612
33712
  };
33613
33713
  }
33614
- replaceMeasureFormula(sheetId, formulaString, newFormulaString) {
33615
- this.history.update("compiledMeasureFormulas", sheetId, formulaString, undefined);
33616
- this.history.update("compiledMeasureFormulas", sheetId, newFormulaString, this.compileMeasureFormula(sheetId, newFormulaString));
33617
- for (const pivotId in this.pivots) {
33618
- const pivot = this.pivots[pivotId];
33619
- if (!pivot) {
33620
- continue;
33621
- }
33622
- for (const measure of pivot.definition.measures) {
33623
- if (measure.computedBy?.formula === formulaString) {
33624
- const measureIndex = pivot.definition.measures.indexOf(measure);
33625
- this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", { formula: newFormulaString, sheetId });
33626
- }
33627
- }
33714
+ replaceMeasureFormula(pivotId, measure, newFormulaString) {
33715
+ const pivot = this.pivots[pivotId];
33716
+ if (!pivot) {
33717
+ return;
33628
33718
  }
33719
+ const measureIndex = pivot.definition.measures.indexOf(measure);
33720
+ this.history.update("pivots", pivotId, "definition", "measures", measureIndex, "computedBy", {
33721
+ formula: newFormulaString,
33722
+ sheetId: measure.computedBy.sheetId,
33723
+ });
33724
+ this.compileCalculatedMeasures(pivotId, pivot.definition.measures);
33629
33725
  }
33630
33726
  checkSortedColumnInMeasures(definition) {
33631
33727
  const measures = definition.measures.map((measure) => measure.id);
@@ -34686,7 +34782,7 @@ class StylePlugin extends CorePlugin {
34686
34782
  case "UPDATE_CELL":
34687
34783
  if (cmd.style !== undefined) {
34688
34784
  if (cmd.style !== null) {
34689
- this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style);
34785
+ this.setStyles(cmd.sheetId, [positionToZone(cmd)], cmd.style, { force: true });
34690
34786
  }
34691
34787
  else {
34692
34788
  this.clearStyle(cmd.sheetId, [positionToZone(cmd)]);
@@ -34754,16 +34850,22 @@ class StylePlugin extends CorePlugin {
34754
34850
  }
34755
34851
  }
34756
34852
  styleIsDefault(style) {
34757
- return deepEquals(this.removeDefaultStyleValues(style), {});
34853
+ for (const key in style) {
34854
+ if (DEFAULT_STYLE_NO_ALIGN[key] !== style[key]) {
34855
+ return false;
34856
+ }
34857
+ }
34858
+ return true;
34758
34859
  }
34759
34860
  removeDefaultStyleValues(style) {
34760
34861
  const cleanedStyle = { ...style };
34761
- for (const property in DEFAULT_STYLE_NO_ALIGN) {
34762
- if (cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34862
+ for (const property in style) {
34863
+ if (cleanedStyle[property] === undefined ||
34864
+ cleanedStyle[property] === DEFAULT_STYLE_NO_ALIGN[property]) {
34763
34865
  delete cleanedStyle[property];
34764
34866
  }
34765
34867
  }
34766
- return cleanedStyle;
34868
+ return Object.keys(cleanedStyle).length > 0 ? cleanedStyle : undefined;
34767
34869
  }
34768
34870
  onMerge(sheetId, zone) {
34769
34871
  this.setStyle(sheetId, zone, this.getCellStyle({ sheetId, col: zone.left, row: zone.top }), {
@@ -34799,13 +34901,13 @@ class StylePlugin extends CorePlugin {
34799
34901
  }
34800
34902
  editingZone = recomputeZones(editingZone, [inter]);
34801
34903
  }
34904
+ style = this.removeDefaultStyleValues(style);
34802
34905
  if (style) {
34803
- const newStyle = this.removeDefaultStyleValues(style);
34804
34906
  styles.push(...editingZone.map((zone) => {
34805
- return { zone, style: newStyle };
34907
+ return { zone, style };
34806
34908
  }));
34807
34909
  }
34808
- this.history.update("styles", sheetId, styles.filter((zoneStyle) => !this.styleIsDefault(zoneStyle.style)));
34910
+ this.history.update("styles", sheetId, styles);
34809
34911
  }
34810
34912
  clearStyle(sheetId, zones) {
34811
34913
  this.setStyles(sheetId, zones, undefined, { force: true });
@@ -40447,14 +40549,16 @@ const PERCENT_FORMAT = "0.00%";
40447
40549
  function withPivotPresentationLayer (PivotClass) {
40448
40550
  class PivotPresentationLayer extends PivotClass {
40449
40551
  getters;
40552
+ pivotId;
40450
40553
  cache = {};
40451
40554
  rankAsc = {};
40452
40555
  rankDesc = {};
40453
40556
  runningTotal = {};
40454
40557
  runningTotalInPercent = {};
40455
- constructor(custom, params) {
40558
+ constructor(pivotId, custom, params) {
40456
40559
  super(custom, params);
40457
40560
  this.getters = params.getters;
40561
+ this.pivotId = pivotId;
40458
40562
  }
40459
40563
  markAsDirtyForEvaluation() {
40460
40564
  this.cache = {};
@@ -40504,7 +40608,7 @@ function withPivotPresentationLayer (PivotClass) {
40504
40608
  return handleError(error, measure.aggregator.toUpperCase());
40505
40609
  }
40506
40610
  }
40507
- const formula = this.getters.getMeasureCompiledFormula(measure);
40611
+ const formula = this.getters.getMeasureCompiledFormula(this.pivotId, measure);
40508
40612
  const getSymbolValue = (symbolName) => {
40509
40613
  const { columns, rows } = this.definition;
40510
40614
  if (columns.find((col) => col.nameWithGranularity === symbolName)) {
@@ -41251,7 +41355,7 @@ class PivotUIPlugin extends CoreViewPlugin {
41251
41355
  const definition = deepCopy(this.getters.getPivotCoreDefinition(pivotId));
41252
41356
  if (!(pivotId in this.pivots)) {
41253
41357
  const Pivot = withPivotPresentationLayer(pivotRegistry.get(definition.type).ui);
41254
- this.pivots[pivotId] = new Pivot(this.custom, { definition, getters: this.getters });
41358
+ this.pivots[pivotId] = new Pivot(pivotId, this.custom, { definition, getters: this.getters });
41255
41359
  }
41256
41360
  else if (recreate) {
41257
41361
  this.pivots[pivotId].onDefinitionChange(definition);
@@ -50243,6 +50347,9 @@ function addStyles(styles) {
50243
50347
  if (style.alignment && style.alignment.wrapText) {
50244
50348
  alignAttrs.push(["wrapText", "1"]);
50245
50349
  }
50350
+ if (style.alignment && style.alignment.textRotation) {
50351
+ alignAttrs.push(["textRotation", style.alignment.textRotation]);
50352
+ }
50246
50353
  if (alignAttrs.length > 0) {
50247
50354
  attributes.push(["applyAlignment", "1"]); // for Libre Office
50248
50355
  styleNodes.push(escapeXml /*xml*/ `<xf ${formatAttributes(attributes)}><alignment ${formatAttributes(alignAttrs)} /></xf> `);
@@ -51523,5 +51630,5 @@ export { BadExpressionError, BasePlugin, CellErrorType, CircularDependencyError,
51523
51630
 
51524
51631
 
51525
51632
  __info__.version = "19.1.0-alpha.3";
51526
- __info__.date = "2025-12-26T10:26:09.971Z";
51527
- __info__.hash = "e6313bd";
51633
+ __info__.date = "2026-01-14T10:01:54.190Z";
51634
+ __info__.hash = "52a3e52";