@odoo/o-spreadsheet 16.4.14 → 16.4.15

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.
@@ -672,8 +672,7 @@ function transpose2dArray(matrix, callback = (val) => val) {
672
672
  *
673
673
  * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions/Character_Classes
674
674
  */
675
- const whiteSpaceCharacters = [
676
- " ",
675
+ const whiteSpaceSpecialCharacters = [
677
676
  "\t",
678
677
  "\f",
679
678
  "\v",
@@ -688,8 +687,7 @@ const whiteSpaceCharacters = [
688
687
  String.fromCharCode(parseInt("3000", 16)),
689
688
  String.fromCharCode(parseInt("feff", 16)),
690
689
  ];
691
- const whiteSpaceRegexp = new RegExp(whiteSpaceCharacters.join("|"), "g");
692
- const newLineRegex = /\r\n|\r|\n/g;
690
+ const whiteSpaceRegexp = new RegExp(whiteSpaceSpecialCharacters.join("|") + "|(\r\n|\r|\n)", "g");
693
691
  /**
694
692
  * Replace all the special spaces in a string (non-breaking, tabs, ...) by normal spaces, and all the
695
693
  * different newlines types by \n.
@@ -697,9 +695,9 @@ const newLineRegex = /\r\n|\r|\n/g;
697
695
  function replaceSpecialSpaces(text) {
698
696
  if (!text)
699
697
  return "";
700
- text = text.replace(whiteSpaceRegexp, " ");
701
- text = text.replace(newLineRegex, NEWLINE);
702
- return text;
698
+ if (!whiteSpaceRegexp.test(text))
699
+ return text;
700
+ return text.replace(whiteSpaceRegexp, (match, newLine) => (newLine ? NEWLINE : " "));
703
701
  }
704
702
  /**
705
703
  * Determine if the numbers are consecutive.
@@ -4269,6 +4267,7 @@ exports.CommandResult = void 0;
4269
4267
  CommandResult[CommandResult["NoActiveSheet"] = 94] = "NoActiveSheet";
4270
4268
  CommandResult[CommandResult["InvalidLocale"] = 95] = "InvalidLocale";
4271
4269
  CommandResult[CommandResult["AlreadyInPaintingFormatMode"] = 96] = "AlreadyInPaintingFormatMode";
4270
+ CommandResult[CommandResult["NoChanges"] = 97] = "NoChanges";
4272
4271
  })(exports.CommandResult || (exports.CommandResult = {}));
4273
4272
 
4274
4273
  const borderStyles = ["thin", "medium", "thick", "dashed", "dotted"];
@@ -4358,12 +4357,12 @@ function toString(value) {
4358
4357
  }
4359
4358
  }
4360
4359
  /** Normalize string by setting it to lowercase and replacing accent letters with plain letters */
4361
- function normalizeString(str) {
4360
+ const normalizeString = memoize(function normalizeString(str) {
4362
4361
  return str
4363
4362
  .toLowerCase()
4364
4363
  .normalize("NFD")
4365
4364
  .replace(/[\u0300-\u036f]/g, "");
4366
- }
4365
+ });
4367
4366
  /**
4368
4367
  * Normalize a value.
4369
4368
  * If the cell value is a string, this will set it to lowercase and replacing accent letters with plain letters
@@ -14174,7 +14173,7 @@ function tokenize(str, locale = DEFAULT_LOCALE) {
14174
14173
  return result;
14175
14174
  }
14176
14175
  function tokenizeDebugger(chars) {
14177
- if (chars.current() === "?") {
14176
+ if (chars.current === "?") {
14178
14177
  chars.shift();
14179
14178
  return { type: "DEBUGGER", value: "?" };
14180
14179
  }
@@ -14185,7 +14184,7 @@ const misc = {
14185
14184
  ")": "RIGHT_PAREN",
14186
14185
  };
14187
14186
  function tokenizeMisc(chars) {
14188
- if (chars.current() in misc) {
14187
+ if (chars.current in misc) {
14189
14188
  const value = chars.shift();
14190
14189
  const type = misc[value];
14191
14190
  return { type, value };
@@ -14193,7 +14192,7 @@ function tokenizeMisc(chars) {
14193
14192
  return null;
14194
14193
  }
14195
14194
  function tokenizeArgsSeparator(chars, locale) {
14196
- if (chars.current() === locale.formulaArgSeparator) {
14195
+ if (chars.current === locale.formulaArgSeparator) {
14197
14196
  const value = chars.shift();
14198
14197
  const type = "ARG_SEPARATOR";
14199
14198
  return { type, value };
@@ -14218,14 +14217,13 @@ function tokenizeNumber(chars, locale) {
14218
14217
  return null;
14219
14218
  }
14220
14219
  function tokenizeString(chars) {
14221
- if (chars.current() === '"') {
14220
+ if (chars.current === '"') {
14222
14221
  const startChar = chars.shift();
14223
14222
  let letters = startChar;
14224
- while (chars.current() &&
14225
- (chars.current() !== startChar || letters[letters.length - 1] === "\\")) {
14223
+ while (chars.current && (chars.current !== startChar || letters[letters.length - 1] === "\\")) {
14226
14224
  letters += chars.shift();
14227
14225
  }
14228
- if (chars.current() === '"') {
14226
+ if (chars.current === '"') {
14229
14227
  letters += chars.shift();
14230
14228
  }
14231
14229
  return {
@@ -14252,14 +14250,14 @@ function tokenizeSymbol(chars) {
14252
14250
  let result = "";
14253
14251
  // there are two main cases to manage: either something which starts with
14254
14252
  // a ', like 'Sheet 2'A2, or a word-like element.
14255
- if (chars.current() === "'") {
14253
+ if (chars.current === "'") {
14256
14254
  let lastChar = chars.shift();
14257
14255
  result += lastChar;
14258
- while (chars.current()) {
14256
+ while (chars.current) {
14259
14257
  lastChar = chars.shift();
14260
14258
  result += lastChar;
14261
14259
  if (lastChar === "'") {
14262
- if (chars.current() && chars.current() === "'") {
14260
+ if (chars.current && chars.current === "'") {
14263
14261
  lastChar = chars.shift();
14264
14262
  result += lastChar;
14265
14263
  }
@@ -14275,7 +14273,7 @@ function tokenizeSymbol(chars) {
14275
14273
  };
14276
14274
  }
14277
14275
  }
14278
- while (chars.current() && separatorRegexp.test(chars.current())) {
14276
+ while (chars.current && separatorRegexp.test(chars.current)) {
14279
14277
  result += chars.shift();
14280
14278
  }
14281
14279
  if (result.length) {
@@ -14290,14 +14288,14 @@ function tokenizeSymbol(chars) {
14290
14288
  }
14291
14289
  function tokenizeSpace(chars) {
14292
14290
  let length = 0;
14293
- while (chars.current() === NEWLINE) {
14291
+ while (chars.current === NEWLINE) {
14294
14292
  length++;
14295
14293
  chars.shift();
14296
14294
  }
14297
14295
  if (length) {
14298
14296
  return { type: "SPACE", value: NEWLINE.repeat(length) };
14299
14297
  }
14300
- while (chars.current() === " ") {
14298
+ while (chars.current === " ") {
14301
14299
  length++;
14302
14300
  chars.shift();
14303
14301
  }
@@ -14316,17 +14314,20 @@ function tokenizeInvalidRange(chars) {
14316
14314
  class TokenizingChars {
14317
14315
  text;
14318
14316
  currentIndex = 0;
14317
+ current;
14319
14318
  constructor(text) {
14320
14319
  this.text = text;
14321
- }
14322
- current() {
14323
- return this.text[this.currentIndex];
14320
+ this.current = text[0];
14324
14321
  }
14325
14322
  shift() {
14326
- return this.text[this.currentIndex++];
14323
+ const current = this.current;
14324
+ const next = this.text[++this.currentIndex];
14325
+ this.current = next;
14326
+ return current;
14327
14327
  }
14328
14328
  advanceBy(length) {
14329
14329
  this.currentIndex += length;
14330
+ this.current = this.text[this.currentIndex];
14330
14331
  }
14331
14332
  isOver() {
14332
14333
  return this.currentIndex >= this.text.length;
@@ -31170,6 +31171,14 @@ class BordersPlugin extends CorePlugin {
31170
31171
  // ---------------------------------------------------------------------------
31171
31172
  // Command Handling
31172
31173
  // ---------------------------------------------------------------------------
31174
+ allowDispatch(cmd) {
31175
+ switch (cmd.type) {
31176
+ case "SET_BORDER":
31177
+ return this.checkBordersUnchanged(cmd);
31178
+ default:
31179
+ return 0 /* CommandResult.Success */;
31180
+ }
31181
+ }
31173
31182
  handle(cmd) {
31174
31183
  switch (cmd.type) {
31175
31184
  case "ADD_MERGE":
@@ -31589,6 +31598,14 @@ class BordersPlugin extends CorePlugin {
31589
31598
  this.setBorders(sheetId, [{ ...zone, left: right }], "right", bordersTopLeft.right);
31590
31599
  }
31591
31600
  }
31601
+ checkBordersUnchanged(cmd) {
31602
+ const currentBorder = this.getCellBorder(cmd);
31603
+ const areAllNewBordersUndefined = !cmd.border?.bottom && !cmd.border?.left && !cmd.border?.right && !cmd.border?.top;
31604
+ if ((!currentBorder && areAllNewBordersUndefined) || deepEquals(currentBorder, cmd.border)) {
31605
+ return 97 /* CommandResult.NoChanges */;
31606
+ }
31607
+ return 0 /* CommandResult.Success */;
31608
+ }
31592
31609
  // ---------------------------------------------------------------------------
31593
31610
  // Import/Export
31594
31611
  // ---------------------------------------------------------------------------
@@ -31696,8 +31713,9 @@ class CellPlugin extends CorePlugin {
31696
31713
  allowDispatch(cmd) {
31697
31714
  switch (cmd.type) {
31698
31715
  case "UPDATE_CELL":
31716
+ return this.checkCellOutOfSheet(cmd);
31699
31717
  case "CLEAR_CELL":
31700
- return this.checkCellOutOfSheet(cmd.sheetId, cmd.col, cmd.row);
31718
+ return this.checkValidations(cmd, this.chainValidations(this.checkCellOutOfSheet, this.checkUselessClearCell));
31701
31719
  default:
31702
31720
  return 0 /* CommandResult.Success */;
31703
31721
  }
@@ -31856,14 +31874,9 @@ class CellPlugin extends CorePlugin {
31856
31874
  */
31857
31875
  getCellById(cellId) {
31858
31876
  // this must be as fast as possible
31859
- for (const sheetId in this.cells) {
31860
- const sheet = this.cells[sheetId];
31861
- const cell = sheet[cellId];
31862
- if (cell) {
31863
- return cell;
31864
- }
31865
- }
31866
- return undefined;
31877
+ const position = this.getters.getCellPosition(cellId);
31878
+ const sheet = this.cells[position.sheetId];
31879
+ return sheet[cellId];
31867
31880
  }
31868
31881
  /*
31869
31882
  * Reconstructs the original formula string based on a normalized form and its dependencies
@@ -32089,13 +32102,23 @@ class CellPlugin extends CorePlugin {
32089
32102
  dependencies: [],
32090
32103
  };
32091
32104
  }
32092
- checkCellOutOfSheet(sheetId, col, row) {
32105
+ checkCellOutOfSheet(cmd) {
32106
+ const { sheetId, col, row } = cmd;
32093
32107
  const sheet = this.getters.tryGetSheet(sheetId);
32094
32108
  if (!sheet)
32095
32109
  return 28 /* CommandResult.InvalidSheetId */;
32096
32110
  const sheetZone = this.getters.getSheetZone(sheetId);
32097
32111
  return isInside(col, row, sheetZone) ? 0 /* CommandResult.Success */ : 19 /* CommandResult.TargetOutOfSheet */;
32098
32112
  }
32113
+ checkUselessClearCell(cmd) {
32114
+ const cell = this.getters.getCell(cmd);
32115
+ if (!cell)
32116
+ return 97 /* CommandResult.NoChanges */;
32117
+ if (!cell.content && !cell.style && !cell.format) {
32118
+ return 97 /* CommandResult.NoChanges */;
32119
+ }
32120
+ return 0 /* CommandResult.Success */;
32121
+ }
32099
32122
  }
32100
32123
  class FormulaCellWithDependencies {
32101
32124
  id;
@@ -35164,10 +35187,13 @@ class SheetPlugin extends CorePlugin {
35164
35187
  // begin with the end.
35165
35188
  rows.sort((a, b) => b - a);
35166
35189
  for (let group of groupConsecutive(rows)) {
35190
+ // indexes are sorted in the descending order
35191
+ const from = group[group.length - 1];
35192
+ const to = group[0];
35167
35193
  // Move the cells.
35168
- this.moveCellOnRowsDeletion(sheet, group[group.length - 1], group[0]);
35169
- // Effectively delete the element and recompute the left-right/top-bottom.
35170
- group.map((row) => this.updateRowsStructureOnDeletion(row, sheet));
35194
+ this.moveCellOnRowsDeletion(sheet, from, to);
35195
+ // Effectively delete the rows
35196
+ this.updateRowsStructureOnDeletion(sheet, from, to);
35171
35197
  }
35172
35198
  const count = rows.filter((row) => row < sheet.panes.ySplit).length;
35173
35199
  if (count) {
@@ -35189,8 +35215,6 @@ class SheetPlugin extends CorePlugin {
35189
35215
  this.addEmptyRows(sheet, quantity);
35190
35216
  // Move the cells.
35191
35217
  this.moveCellsOnAddition(sheet, index, quantity, "rows");
35192
- // Recompute the left-right/top-bottom.
35193
- this.updateRowsStructureOnAddition(sheet, row, quantity);
35194
35218
  if (index < sheet.panes.ySplit) {
35195
35219
  this.setPaneDivisions(sheet.id, sheet.panes.ySplit + quantity, "ROW");
35196
35220
  }
@@ -35291,35 +35315,20 @@ class SheetPlugin extends CorePlugin {
35291
35315
  }
35292
35316
  }
35293
35317
  }
35294
- updateRowsStructureOnDeletion(index, sheet) {
35318
+ updateRowsStructureOnDeletion(sheet, deleteFromRow, deleteToRow) {
35295
35319
  const rows = [];
35296
- const cellsQueue = sheet.rows.map((row) => row.cells);
35320
+ const cellsQueue = sheet.rows.map((row) => row.cells).reverse();
35297
35321
  for (let i in sheet.rows) {
35298
- if (Number(i) === index) {
35322
+ const row = Number(i);
35323
+ if (row >= deleteFromRow && row <= deleteToRow) {
35299
35324
  continue;
35300
35325
  }
35301
35326
  rows.push({
35302
- cells: cellsQueue.shift(),
35327
+ cells: cellsQueue.pop(),
35303
35328
  });
35304
35329
  }
35305
35330
  this.history.update("sheets", sheet.id, "rows", rows);
35306
35331
  }
35307
- /**
35308
- * Update the rows of the sheet after an addition:
35309
- * - Rename the rows
35310
- *
35311
- * @param sheet Sheet on which the deletion occurs
35312
- * @param addedRow Index of the added row
35313
- * @param rowsToAdd Number of the rows to add
35314
- */
35315
- updateRowsStructureOnAddition(sheet, addedRow, rowsToAdd) {
35316
- const rows = [];
35317
- const cellsQueue = sheet.rows.map((row) => row.cells);
35318
- sheet.rows.forEach(() => rows.push({
35319
- cells: cellsQueue.shift(),
35320
- }));
35321
- this.history.update("sheets", sheet.id, "rows", rows);
35322
- }
35323
35332
  /**
35324
35333
  * Add empty rows at the end of the rows
35325
35334
  *
@@ -35435,6 +35444,7 @@ class CompilationParametersBuilder {
35435
35444
  getters;
35436
35445
  computeCell;
35437
35446
  evalContext;
35447
+ rangeCache = {};
35438
35448
  constructor(context, getters, computeCell) {
35439
35449
  this.getters = getters;
35440
35450
  this.computeCell = computeCell;
@@ -35520,25 +35530,32 @@ class CompilationParametersBuilder {
35520
35530
  if (!_zone) {
35521
35531
  return { value: [[]], format: [[]] };
35522
35532
  }
35533
+ const { top, left, bottom, right } = zone;
35534
+ const cacheKey = `${sheetId}-${top}-${left}-${bottom}-${right}`;
35535
+ if (cacheKey in this.rangeCache) {
35536
+ return this.rangeCache[cacheKey];
35537
+ }
35523
35538
  const height = _zone.bottom - _zone.top + 1;
35524
35539
  const width = _zone.right - _zone.left + 1;
35525
- const value = Array.from({ length: width }, () => Array.from({ length: height }));
35526
- const format = Array.from({ length: width }, () => Array.from({ length: height }));
35540
+ const value = new Array(width);
35541
+ const format = new Array(width);
35527
35542
  // Performance issue: nested loop is faster than a map here
35528
35543
  for (let col = _zone.left; col <= _zone.right; col++) {
35544
+ const colIndex = col - _zone.left;
35545
+ value[colIndex] = new Array(height);
35546
+ format[colIndex] = new Array(height);
35529
35547
  for (let row = _zone.top; row <= _zone.bottom; row++) {
35530
- const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId: sheetId, col, row });
35531
- if (evaluatedCell) {
35532
- const colIndex = col - _zone.left;
35533
- const rowIndex = row - _zone.top;
35534
- value[colIndex][rowIndex] = evaluatedCell.value;
35535
- if (evaluatedCell.format !== undefined) {
35536
- format[colIndex][rowIndex] = evaluatedCell.format;
35537
- }
35548
+ const evaluatedCell = this.getEvaluatedCellIfNotEmpty({ sheetId, col, row });
35549
+ const rowIndex = row - _zone.top;
35550
+ value[colIndex][rowIndex] = evaluatedCell?.value;
35551
+ if (evaluatedCell?.format !== undefined) {
35552
+ format[colIndex][rowIndex] = evaluatedCell.format;
35538
35553
  }
35539
35554
  }
35540
35555
  }
35541
- return { value, format };
35556
+ const result = { value, format };
35557
+ this.rangeCache[cacheKey] = result;
35558
+ return result;
35542
35559
  }
35543
35560
  }
35544
35561
 
@@ -35736,6 +35753,7 @@ class Evaluator {
35736
35753
  this.formulaDependencies().addDependencies(positionId, dependencies);
35737
35754
  }
35738
35755
  updateCompilationParameters() {
35756
+ // rebuild the compilation parameters (with a clean cache)
35739
35757
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
35740
35758
  }
35741
35759
  evaluateCells(positions) {
@@ -35779,6 +35797,15 @@ class Evaluator {
35779
35797
  this.evaluatedCells = new Map();
35780
35798
  this.evaluate(this.getAllCells());
35781
35799
  }
35800
+ evaluateFormula(sheetId, formulaString) {
35801
+ const compiledFormula = compile(formulaString);
35802
+ const ranges = [];
35803
+ for (let xc of compiledFormula.dependencies) {
35804
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
35805
+ }
35806
+ this.updateCompilationParameters();
35807
+ return compiledFormula.execute(ranges, ...this.compilationParams).value;
35808
+ }
35782
35809
  getAllCells() {
35783
35810
  const positionIds = new JetSet();
35784
35811
  for (const sheetId of this.getters.getSheetIds()) {
@@ -35805,6 +35832,7 @@ class Evaluator {
35805
35832
  this.nextPositionsToUpdate = cells;
35806
35833
  let currentIteration = 0;
35807
35834
  while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
35835
+ this.updateCompilationParameters();
35808
35836
  const positionIds = Array.from(this.nextPositionsToUpdate);
35809
35837
  this.nextPositionsToUpdate.clear();
35810
35838
  for (let i = 0; i < positionIds.length; ++i) {
@@ -36189,7 +36217,6 @@ class PositionBitsEncoder {
36189
36217
  // of other cells depending on it, at the next iteration.
36190
36218
  //#endregion
36191
36219
  class EvaluationPlugin extends UIPlugin {
36192
- config;
36193
36220
  static getters = [
36194
36221
  "evaluateFormula",
36195
36222
  "getRangeFormattedValues",
@@ -36201,12 +36228,9 @@ class EvaluationPlugin extends UIPlugin {
36201
36228
  ];
36202
36229
  shouldRebuildDependenciesGraph = true;
36203
36230
  evaluator;
36204
- compilationParams;
36205
36231
  positionsToUpdate = [];
36206
36232
  constructor(config) {
36207
36233
  super(config);
36208
- this.config = config;
36209
- this.compilationParams = this.getCompilationParameters();
36210
36234
  this.evaluator = new Evaluator(config.custom, this.getters);
36211
36235
  }
36212
36236
  // ---------------------------------------------------------------------------
@@ -36231,10 +36255,6 @@ class EvaluationPlugin extends UIPlugin {
36231
36255
  case "EVALUATE_CELLS":
36232
36256
  this.evaluator.evaluateAllCells();
36233
36257
  break;
36234
- case "UPDATE_LOCALE":
36235
- this.compilationParams = this.getCompilationParameters();
36236
- this.evaluator.updateCompilationParameters();
36237
- break;
36238
36258
  }
36239
36259
  }
36240
36260
  finalize() {
@@ -36252,12 +36272,7 @@ class EvaluationPlugin extends UIPlugin {
36252
36272
  // Getters
36253
36273
  // ---------------------------------------------------------------------------
36254
36274
  evaluateFormula(sheetId, formulaString) {
36255
- const compiledFormula = compile(formulaString);
36256
- const ranges = [];
36257
- for (let xc of compiledFormula.dependencies) {
36258
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
36259
- }
36260
- return compiledFormula.execute(ranges, ...this.compilationParams).value;
36275
+ return this.evaluator.evaluateFormula(sheetId, formulaString);
36261
36276
  }
36262
36277
  /**
36263
36278
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -36356,9 +36371,6 @@ class EvaluationPlugin extends UIPlugin {
36356
36371
  }
36357
36372
  return undefined;
36358
36373
  }
36359
- getCompilationParameters() {
36360
- return buildCompilationParameters(this.config.custom, this.getters, (position) => this.evaluator.getEvaluatedCell(position));
36361
- }
36362
36374
  }
36363
36375
  function isBadExpression(formula) {
36364
36376
  try {
@@ -42075,8 +42087,8 @@ class ClipboardPlugin extends UIPlugin {
42075
42087
  this.lastPasteState = this.state;
42076
42088
  if (this.paintFormatStatus === "oneOff") {
42077
42089
  this.paintFormatStatus = "inactive";
42078
- this.status = "invisible";
42079
42090
  }
42091
+ this.status = "invisible";
42080
42092
  break;
42081
42093
  case "CLEAN_CLIPBOARD_HIGHLIGHT":
42082
42094
  this.status = "invisible";
@@ -47893,9 +47905,9 @@ function revertChanges(revisions) {
47893
47905
  * Apply the changes of the given HistoryChange to the state
47894
47906
  */
47895
47907
  function applyChange(change, target) {
47896
- let val = change.root;
47897
- let key = change.path[change.path.length - 1];
47898
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
47908
+ let val = change.path[0];
47909
+ const key = change.path[change.path.length - 1];
47910
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
47899
47911
  const p = change.path[pathIndex];
47900
47912
  if (val[p] === undefined) {
47901
47913
  const nextPath = change.path[pathIndex + 1];
@@ -48576,13 +48588,14 @@ class StateObserver {
48576
48588
  }
48577
48589
  addChange(...args) {
48578
48590
  const val = args.pop();
48579
- const [root, ...path] = args;
48591
+ const root = args[0];
48580
48592
  let value = root;
48581
- let key = path[path.length - 1];
48582
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
48583
- const p = path[pathIndex];
48593
+ let key = args[args.length - 1];
48594
+ const pathLength = args.length - 2;
48595
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
48596
+ const p = args[pathIndex];
48584
48597
  if (value[p] === undefined) {
48585
- const nextPath = path[pathIndex + 1];
48598
+ const nextPath = args[pathIndex + 1];
48586
48599
  value[p] = createEmptyStructure(nextPath);
48587
48600
  }
48588
48601
  value = value[p];
@@ -48591,8 +48604,7 @@ class StateObserver {
48591
48604
  return;
48592
48605
  }
48593
48606
  this.changes.push({
48594
- root,
48595
- path,
48607
+ path: args,
48596
48608
  before: value[key],
48597
48609
  after: val,
48598
48610
  });
@@ -50442,19 +50454,22 @@ class Model extends EventBus {
50442
50454
  * Check if the given command is allowed by all the plugins and the history.
50443
50455
  */
50444
50456
  checkDispatchAllowed(command) {
50445
- if (isCoreCommand(command)) {
50446
- return this.checkDispatchAllowedCoreCommand(command);
50457
+ const results = isCoreCommand(command)
50458
+ ? this.checkDispatchAllowedCoreCommand(command)
50459
+ : this.checkDispatchAllowedLocalCommand(command);
50460
+ if (results.some((r) => r !== 0 /* CommandResult.Success */)) {
50461
+ return new DispatchResult(results.flat());
50447
50462
  }
50448
- return this.checkDispatchAllowedLocalCommand(command);
50463
+ return DispatchResult.Success;
50449
50464
  }
50450
50465
  checkDispatchAllowedCoreCommand(command) {
50451
50466
  const results = this.corePlugins.map((handler) => handler.allowDispatch(command));
50452
50467
  results.push(this.range.allowDispatch(command));
50453
- return new DispatchResult(results.flat());
50468
+ return results;
50454
50469
  }
50455
50470
  checkDispatchAllowedLocalCommand(command) {
50456
50471
  const results = this.uiHandlers.map((handler) => handler.allowDispatch(command));
50457
- return new DispatchResult(results.flat());
50472
+ return results;
50458
50473
  }
50459
50474
  finalize() {
50460
50475
  this.status = 3 /* Status.Finalizing */;
@@ -50778,6 +50793,6 @@ exports.setTranslationMethod = setTranslationMethod;
50778
50793
  exports.tokenize = tokenize;
50779
50794
 
50780
50795
 
50781
- __info__.version = '16.4.14';
50782
- __info__.date = '2023-11-16T11:59:51.900Z';
50783
- __info__.hash = '66c6f47';
50796
+ __info__.version = '16.4.15';
50797
+ __info__.date = '2023-11-24T13:12:26.608Z';
50798
+ __info__.hash = '141943d';
@@ -1287,7 +1287,7 @@ declare class StateObserver {
1287
1287
  commands: CoreCommand[];
1288
1288
  };
1289
1289
  addCommand(command: CoreCommand): void;
1290
- addChange(...args: any[]): void;
1290
+ addChange(...args: [...HistoryChange["path"], any]): void;
1291
1291
  }
1292
1292
 
1293
1293
  interface Validator {
@@ -2382,7 +2382,8 @@ declare const enum CommandResult {
2382
2382
  NoSplitSeparatorInSelection = 93,
2383
2383
  NoActiveSheet = 94,
2384
2384
  InvalidLocale = 95,
2385
- AlreadyInPaintingFormatMode = 96
2385
+ AlreadyInPaintingFormatMode = 96,
2386
+ NoChanges = 97
2386
2387
  }
2387
2388
  interface CommandHandler<T> {
2388
2389
  allowDispatch(command: T): CommandResult | CommandResult[];
@@ -3016,7 +3017,8 @@ interface BordersPluginState {
3016
3017
  declare class BordersPlugin extends CorePlugin<BordersPluginState> implements BordersPluginState {
3017
3018
  static getters: readonly ["getCellBorder", "getBordersColors"];
3018
3019
  readonly borders: BordersPluginState["borders"];
3019
- handle(cmd: Command): void;
3020
+ allowDispatch(cmd: CoreCommand): CommandResult.Success | CommandResult.NoChanges;
3021
+ handle(cmd: CoreCommand): void;
3020
3022
  /**
3021
3023
  * Move borders according to the inserted columns.
3022
3024
  * Ensure borders continuity.
@@ -3114,6 +3116,7 @@ declare class BordersPlugin extends CorePlugin<BordersPluginState> implements Bo
3114
3116
  * Compute the borders to add to the given zone merged.
3115
3117
  */
3116
3118
  private addBordersToMerge;
3119
+ private checkBordersUnchanged;
3117
3120
  import(data: WorkbookData): void;
3118
3121
  export(data: WorkbookData): void;
3119
3122
  exportForExcel(data: ExcelWorkbookData): void;
@@ -3138,7 +3141,7 @@ declare class CellPlugin extends CorePlugin<CoreState> implements CoreState {
3138
3141
  };
3139
3142
  };
3140
3143
  adaptRanges(applyChange: ApplyRangeChange, sheetId?: UID): void;
3141
- allowDispatch(cmd: CoreCommand): CommandResult;
3144
+ allowDispatch(cmd: CoreCommand): CommandResult | CommandResult[];
3142
3145
  handle(cmd: CoreCommand): void;
3143
3146
  /**
3144
3147
  * Set a format to all the cells in a zone
@@ -3211,6 +3214,7 @@ declare class CellPlugin extends CorePlugin<CoreState> implements CoreState {
3211
3214
  private createFormulaCellWithDependencies;
3212
3215
  private createErrorFormula;
3213
3216
  private checkCellOutOfSheet;
3217
+ private checkUselessClearCell;
3214
3218
  }
3215
3219
 
3216
3220
  /**
@@ -3730,15 +3734,6 @@ declare class SheetPlugin extends CorePlugin<SheetState$1> implements SheetState
3730
3734
  */
3731
3735
  private moveCellOnRowsDeletion;
3732
3736
  private updateRowsStructureOnDeletion;
3733
- /**
3734
- * Update the rows of the sheet after an addition:
3735
- * - Rename the rows
3736
- *
3737
- * @param sheet Sheet on which the deletion occurs
3738
- * @param addedRow Index of the added row
3739
- * @param rowsToAdd Number of the rows to add
3740
- */
3741
- private updateRowsStructureOnAddition;
3742
3737
  /**
3743
3738
  * Add empty rows at the end of the rows
3744
3739
  *
@@ -3760,11 +3755,9 @@ declare class SheetPlugin extends CorePlugin<SheetState$1> implements SheetState
3760
3755
  }
3761
3756
 
3762
3757
  declare class EvaluationPlugin extends UIPlugin {
3763
- private config;
3764
3758
  static getters: readonly ["evaluateFormula", "getRangeFormattedValues", "getRangeValues", "getRangeFormats", "getEvaluatedCell", "getEvaluatedCells", "getEvaluatedCellsInZone"];
3765
3759
  private shouldRebuildDependenciesGraph;
3766
3760
  private evaluator;
3767
- private compilationParams;
3768
3761
  private positionsToUpdate;
3769
3762
  constructor(config: UIPluginConfig);
3770
3763
  beforeHandle(cmd: Command): void;
@@ -3793,7 +3786,6 @@ declare class EvaluationPlugin extends UIPlugin {
3793
3786
  * formula of the array formula that spreads to the cell
3794
3787
  */
3795
3788
  private getCorrespondingFormulaCell;
3796
- private getCompilationParameters;
3797
3789
  }
3798
3790
 
3799
3791
  interface CustomColorState {
@@ -4890,8 +4882,7 @@ type Getters = {
4890
4882
  } & LocalHistoryGetters & CoreGetters & AutofillGetters & AutomaticSumGetters & ClipboardGetters & EditionGetters & EvaluationGetters & EvaluationChartGetters & EvaluationConditionalFormatGetters & FindAndReplaceGetters & HighlightGetters & CustomColorsGetters & RendererGetters & SelectionGetters & SelectionInputGetters & CollaborativeGetters & SortGetters & UIOptionsGetters & SheetUIGetters & ViewportGetters & CellPopoverPluginGetters & FilterEvaluationGetters & HeaderVisibilityIUIGetters & SplitToColumnsGetters & UIRowSizeGetters;
4891
4883
 
4892
4884
  interface HistoryChange {
4893
- root: any;
4894
- path: (string | number)[];
4885
+ path: [any, ...(number | string)[]];
4895
4886
  before: any;
4896
4887
  after: any;
4897
4888
  }