@odoo/o-spreadsheet 17.2.0-alpha.8 → 17.2.0

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,9 +3,9 @@
3
3
  /**
4
4
  * This file is generated by o-spreadsheet build tools. Do not edit it.
5
5
  * @see https://github.com/odoo/o-spreadsheet
6
- * @version 17.2.0-alpha.8
7
- * @date 2024-03-15T11:01:01.388Z
8
- * @hash 11cf381
6
+ * @version 17.2.0
7
+ * @date 2024-03-20T08:12:44.398Z
8
+ * @hash 1869c24
9
9
  */
10
10
 
11
11
  import { reactive, useEnv, useSubEnv, useState, onWillUnmount, markRaw, toRaw, Component, useRef, onMounted, useEffect, onPatched, useComponent, onWillPatch, onWillUpdateProps, useExternalListener, onWillStart, xml, useChildSubEnv } from '@odoo/owl';
@@ -640,21 +640,6 @@ function isConsecutive(iterable) {
640
640
  }
641
641
  return true;
642
642
  }
643
- class JetSet extends Set {
644
- addMany(iterable) {
645
- for (const element of iterable) {
646
- super.add(element);
647
- }
648
- return this;
649
- }
650
- deleteMany(iterable) {
651
- let wasDeleted = false;
652
- for (const element of iterable) {
653
- wasDeleted ||= super.delete(element);
654
- }
655
- return wasDeleted;
656
- }
657
- }
658
643
  /**
659
644
  * Creates a version of the function that's memoized on the value of its first
660
645
  * argument, if any.
@@ -4100,14 +4085,6 @@ function positions(zone) {
4100
4085
  }
4101
4086
  return positions;
4102
4087
  }
4103
- function forEachPositionsInZone(zone, callback) {
4104
- const { left, right, top, bottom } = zone;
4105
- for (let col = left; col <= right; col++) {
4106
- for (let row = top; row <= bottom; row++) {
4107
- callback(col, row);
4108
- }
4109
- }
4110
- }
4111
4088
  /**
4112
4089
  * This function returns a zone with coordinates modified according to the change
4113
4090
  * applied to the zone. It may be possible to change the zone by resizing or moving
@@ -10053,6 +10030,9 @@ function makeArg(str, description) {
10053
10030
  result.default = true;
10054
10031
  result.defaultValue = defaultValue;
10055
10032
  }
10033
+ if (types.some((t) => t.startsWith("RANGE"))) {
10034
+ result.acceptMatrix = true;
10035
+ }
10056
10036
  return result;
10057
10037
  }
10058
10038
  /**
@@ -18623,11 +18603,27 @@ class FunctionRegistry extends Registry {
18623
18603
  }
18624
18604
  const descr = addMetaInfoFromArg(addDescr);
18625
18605
  validateArguments(descr.args);
18626
- this.mapping[name] = addErrorHandling(addResultHandling(descr.compute), name);
18606
+ this.mapping[name] = addErrorHandling(addResultHandling(addInputHandling(descr)), name);
18627
18607
  super.add(name, descr);
18628
18608
  return this;
18629
18609
  }
18630
18610
  }
18611
+ function addInputHandling(descr) {
18612
+ function computeWithInputHandling(...args) {
18613
+ for (let i = 0; i < args.length; i++) {
18614
+ const argDefinition = descr.args[descr.getArgToFocus(i + 1) - 1];
18615
+ const arg = args[i];
18616
+ if (isMatrix(arg) && !argDefinition.acceptMatrix) {
18617
+ if (arg.length !== 1 || arg[0].length !== 1) {
18618
+ throw new EvaluationError(_t("Function [[FUNCTION_NAME]] expects the parameter '%s' to be a single value or a single cell reference, not a range.", argDefinition.name));
18619
+ }
18620
+ args[i] = arg[0][0];
18621
+ }
18622
+ }
18623
+ return descr.compute.apply(this, args);
18624
+ }
18625
+ return computeWithInputHandling;
18626
+ }
18631
18627
  function addErrorHandling(compute, functionName) {
18632
18628
  return function (...args) {
18633
18629
  try {
@@ -45849,6 +45845,41 @@ class CompilationParametersBuilder {
45849
45845
  }
45850
45846
  }
45851
45847
 
45848
+ class PositionMap {
45849
+ map = {};
45850
+ set({ sheetId, col, row }, value) {
45851
+ const map = this.map;
45852
+ if (!map[sheetId]) {
45853
+ map[sheetId] = {};
45854
+ }
45855
+ if (!map[sheetId][col]) {
45856
+ map[sheetId][col] = {};
45857
+ }
45858
+ map[sheetId][col][row] = value;
45859
+ }
45860
+ get({ sheetId, col, row }) {
45861
+ return this.map[sheetId]?.[col]?.[row];
45862
+ }
45863
+ has({ sheetId, col, row }) {
45864
+ return this.map[sheetId]?.[col]?.[row] !== undefined;
45865
+ }
45866
+ delete({ sheetId, col, row }) {
45867
+ delete this.map[sheetId]?.[col]?.[row];
45868
+ }
45869
+ keys() {
45870
+ const map = this.map;
45871
+ const keys = [];
45872
+ for (const sheetId in map) {
45873
+ for (const col in map[sheetId]) {
45874
+ for (const row in map[sheetId][col]) {
45875
+ keys.push({ sheetId, col: parseInt(col), row: parseInt(row) });
45876
+ }
45877
+ }
45878
+ }
45879
+ return keys;
45880
+ }
45881
+ }
45882
+
45852
45883
  function quickselect(arr, k, left, right, compare) {
45853
45884
  quickselectStep(arr, k, left || 0, right || (arr.length - 1), compare || defaultCompare);
45854
45885
  }
@@ -46575,26 +46606,26 @@ class ZoneRBush extends RBush {
46575
46606
  * It uses an R-Tree data structure to efficiently find dependent cells.
46576
46607
  */
46577
46608
  class FormulaDependencyGraph {
46578
- encoder;
46579
- dependencies = new Map();
46609
+ createEmptyPositionSet;
46610
+ dependencies = new PositionMap();
46580
46611
  rTree;
46581
- constructor(encoder, data = []) {
46582
- this.encoder = encoder;
46612
+ constructor(createEmptyPositionSet, data = []) {
46613
+ this.createEmptyPositionSet = createEmptyPositionSet;
46583
46614
  this.rTree = new SpreadsheetRTree(data);
46584
46615
  }
46585
- removeAllDependencies(formulaPositionId) {
46586
- const ranges = this.dependencies.get(formulaPositionId);
46616
+ removeAllDependencies(formulaPosition) {
46617
+ const ranges = this.dependencies.get(formulaPosition);
46587
46618
  if (!ranges) {
46588
46619
  return;
46589
46620
  }
46590
46621
  for (const range of ranges) {
46591
46622
  this.rTree.remove(range);
46592
46623
  }
46593
- this.dependencies.delete(formulaPositionId);
46624
+ this.dependencies.delete(formulaPosition);
46594
46625
  }
46595
- addDependencies(formulaPositionId, dependencies) {
46626
+ addDependencies(formulaPosition, dependencies) {
46596
46627
  const rTreeItems = dependencies.map(({ sheetId, zone }) => ({
46597
- data: formulaPositionId,
46628
+ data: formulaPosition,
46598
46629
  boundingBox: {
46599
46630
  zone,
46600
46631
  sheetId,
@@ -46603,12 +46634,12 @@ class FormulaDependencyGraph {
46603
46634
  for (const item of rTreeItems) {
46604
46635
  this.rTree.insert(item);
46605
46636
  }
46606
- const existingDependencies = this.dependencies.get(formulaPositionId);
46637
+ const existingDependencies = this.dependencies.get(formulaPosition);
46607
46638
  if (existingDependencies) {
46608
46639
  existingDependencies.push(...rTreeItems);
46609
46640
  }
46610
46641
  else {
46611
- this.dependencies.set(formulaPositionId, rTreeItems);
46642
+ this.dependencies.set(formulaPosition, rTreeItems);
46612
46643
  }
46613
46644
  }
46614
46645
  /**
@@ -46617,23 +46648,194 @@ class FormulaDependencyGraph {
46617
46648
  * This is called a topological ordering (excluding cycles)
46618
46649
  */
46619
46650
  getCellsDependingOn(ranges) {
46620
- const visited = new JetSet();
46651
+ const visited = this.createEmptyPositionSet();
46621
46652
  const queue = Array.from(ranges).reverse();
46622
46653
  while (queue.length > 0) {
46623
46654
  const range = queue.pop();
46624
- visited.addMany(this.encoder.encodeBoundingBox(range));
46625
- const impactedPositionIds = this.rTree.search(range).map((dep) => dep.data);
46626
- for (const positionId of impactedPositionIds) {
46627
- if (!visited.has(positionId)) {
46628
- queue.push(this.encoder.decodeToBoundingBox(positionId));
46655
+ visited.addMany(positions(range.zone).map((position) => ({ sheetId: range.sheetId, ...position })));
46656
+ const impactedPositions = this.rTree.search(range).map((dep) => dep.data);
46657
+ for (const position of impactedPositions) {
46658
+ if (!visited.has(position)) {
46659
+ queue.push({ sheetId: position.sheetId, zone: positionToZone(position) });
46629
46660
  }
46630
46661
  }
46631
46662
  }
46632
- visited.deleteMany(ranges.flatMap((r) => this.encoder.encodeBoundingBox(r)));
46663
+ visited.deleteMany(ranges.flatMap((r) => positions(r.zone).map((position) => ({ sheetId: r.sheetId, ...position }))));
46633
46664
  return visited;
46634
46665
  }
46635
46666
  }
46636
46667
 
46668
+ /**
46669
+ * Implements a fixed-sized grid or 2D matrix of bits.
46670
+ * based on https://github.com/zandaqo/structurae
46671
+ *
46672
+ * The grid is implemented as a 1D array of 32-bit integers, where each bit represents a cell in the grid.
46673
+ * It follows row-major order, with each row stored consecutively in 32-bit blocks.
46674
+ * Pads the number of columns to the next power of 2 to allow quick lookups with bitwise operations.
46675
+ *
46676
+ * Key terminology:
46677
+ * - bucket: Index of an item in the Uint32Array, a 32-bit integer.
46678
+ * - bitPosition: The position of a bit within the bucket 32-bit integer.
46679
+ */
46680
+ class BinaryGrid extends Uint32Array {
46681
+ columnOffset = 0;
46682
+ cols = 0;
46683
+ rows = 0;
46684
+ /**
46685
+ * Creates a binary grid of specified dimensions.
46686
+ */
46687
+ static create(rows, columns) {
46688
+ const columnOffset = log2Ceil(columns);
46689
+ const length = (rows << columnOffset) >> 5;
46690
+ const grid = new this(length + 1);
46691
+ grid.columnOffset = columnOffset;
46692
+ grid.cols = columns;
46693
+ grid.rows = rows;
46694
+ return grid;
46695
+ }
46696
+ /**
46697
+ * Returns the bit at given coordinates.
46698
+ */
46699
+ getValue(position) {
46700
+ const [bucket, bitPosition] = this.getCoordinates(position);
46701
+ return ((this[bucket] >> bitPosition) & 1);
46702
+ }
46703
+ /**
46704
+ * Sets the bit at given coordinates.
46705
+ */
46706
+ setValue(position, value) {
46707
+ const [bucket, bitPosition] = this.getCoordinates(position);
46708
+ const currentValue = (this[bucket] >> bitPosition) & 1;
46709
+ const hasBeenInserted = currentValue === 0 && value === 1;
46710
+ this[bucket] = (this[bucket] & ~(1 << bitPosition)) | (value << bitPosition);
46711
+ return hasBeenInserted;
46712
+ // Let's breakdown of the above line:
46713
+ // with an example with a 4-bit integer (instead of 32-bit).
46714
+ //
46715
+ // Let's say we want to set the bit at position 2 to 1 and the existing
46716
+ // bit sequence this[bucket] is 1001. The final bit sequence should be 1101.
46717
+ //
46718
+ // First, we clear the bit at position 2 by AND-ing this[bucket] with a
46719
+ // mask having all 1s except a 0 at the bit position (~ (1 << bitPosition)).
46720
+ // 1 << bitPosition is 0100 (shifting 0001 to the left by 2)
46721
+ // Inverting the bits with ~ gives the final mask ~(1 << bitPosition): 1011
46722
+ //
46723
+ // Then, we shift the value by the bit position (value << bitPosition: 0100)
46724
+ // and OR the result with the previous step's result:
46725
+ // (1001 & 1011) | 0100 = 1101
46726
+ }
46727
+ isEmpty() {
46728
+ return !this.some((bucket) => bucket !== 0);
46729
+ }
46730
+ fillAllPositions() {
46731
+ const thirtyTwoOnes = -1 >>> 0; // same as 2 ** 32 - 1, a 32-bit number with all bits set to 1
46732
+ this.fill(thirtyTwoOnes);
46733
+ }
46734
+ clear() {
46735
+ this.fill(0);
46736
+ }
46737
+ getCoordinates(position) {
46738
+ const { row, col } = position;
46739
+ const index = (row << this.columnOffset) + col;
46740
+ const bucket = index >> 5;
46741
+ return [bucket, index - (bucket << 5)];
46742
+ }
46743
+ }
46744
+ function log2Ceil(value) {
46745
+ // A faster version of Math.ceil(Math.log2(value)).
46746
+ if (value === 0) {
46747
+ return -Infinity;
46748
+ }
46749
+ else if (value < 0) {
46750
+ return NaN;
46751
+ }
46752
+ // --value handles the case where value is a power of 2
46753
+ return 32 - Math.clz32(--value);
46754
+ }
46755
+
46756
+ class PositionSet {
46757
+ sheets = {};
46758
+ /**
46759
+ * List of positions in the order they were inserted.
46760
+ */
46761
+ insertions = [];
46762
+ maxSize = 0;
46763
+ constructor(sheetSizes) {
46764
+ for (const sheetId in sheetSizes) {
46765
+ const cols = sheetSizes[sheetId].cols;
46766
+ const rows = sheetSizes[sheetId].rows;
46767
+ this.maxSize += cols * rows;
46768
+ this.sheets[sheetId] = BinaryGrid.create(rows, cols);
46769
+ }
46770
+ }
46771
+ add(position) {
46772
+ const hasBeenInserted = this.sheets[position.sheetId].setValue(position, 1);
46773
+ if (hasBeenInserted) {
46774
+ this.insertions.push(position);
46775
+ }
46776
+ }
46777
+ addMany(positions) {
46778
+ for (const position of positions) {
46779
+ this.add(position);
46780
+ }
46781
+ }
46782
+ delete(position) {
46783
+ this.sheets[position.sheetId].setValue(position, 0);
46784
+ }
46785
+ deleteMany(positions) {
46786
+ for (const position of positions) {
46787
+ this.delete(position);
46788
+ }
46789
+ }
46790
+ has(position) {
46791
+ return this.sheets[position.sheetId].getValue(position) === 1;
46792
+ }
46793
+ clear() {
46794
+ const insertions = this.insertions;
46795
+ this.insertions = [];
46796
+ for (const sheetId in this.sheets) {
46797
+ this.sheets[sheetId].clear();
46798
+ }
46799
+ return insertions;
46800
+ }
46801
+ isEmpty() {
46802
+ if (this.insertions.length === 0) {
46803
+ return true;
46804
+ }
46805
+ for (const sheetId in this.sheets) {
46806
+ if (!this.sheets[sheetId].isEmpty()) {
46807
+ return false;
46808
+ }
46809
+ }
46810
+ return true;
46811
+ }
46812
+ fillAllPositions() {
46813
+ this.insertions = new Array(this.maxSize);
46814
+ let index = 0;
46815
+ for (const sheetId in this.sheets) {
46816
+ const grid = this.sheets[sheetId];
46817
+ grid.fillAllPositions();
46818
+ for (let i = 0; i < grid.rows; i++) {
46819
+ for (let j = 0; j < grid.cols; j++) {
46820
+ this.insertions[index++] = { sheetId, row: i, col: j };
46821
+ }
46822
+ }
46823
+ }
46824
+ }
46825
+ /**
46826
+ * Iterate over the positions in the order of insertion.
46827
+ * Note that the same position may be yielded multiple times if the value was added
46828
+ * to the set then removed and then added again.
46829
+ */
46830
+ *[Symbol.iterator]() {
46831
+ for (const position of this.insertions) {
46832
+ if (this.sheets[position.sheetId].getValue(position) === 1) {
46833
+ yield position;
46834
+ }
46835
+ }
46836
+ }
46837
+ }
46838
+
46637
46839
  /**
46638
46840
  * Contains, for each cell, the array
46639
46841
  * formulas that could potentially spread on it
@@ -46647,6 +46849,7 @@ class FormulaDependencyGraph {
46647
46849
  *
46648
46850
  */
46649
46851
  class SpreadingRelation {
46852
+ createEmptyPositionSet;
46650
46853
  /**
46651
46854
  * Internal structure:
46652
46855
  * For something like
@@ -46675,39 +46878,42 @@ class SpreadingRelation {
46675
46878
  * - (B1) --> (B2, B3, B4) meaning B1 spreads on B2, B3 and B4
46676
46879
  *
46677
46880
  */
46678
- resultsToArrayFormulas = new Map();
46679
- arrayFormulasToResults = new Map();
46680
- getFormulaPositionsSpreadingOn(resultPositionId) {
46681
- return this.resultsToArrayFormulas.get(resultPositionId) || EMPTY_ARRAY;
46881
+ resultsToArrayFormulas = new PositionMap();
46882
+ arrayFormulasToResults = new PositionMap();
46883
+ constructor(createEmptyPositionSet) {
46884
+ this.createEmptyPositionSet = createEmptyPositionSet;
46885
+ }
46886
+ getFormulaPositionsSpreadingOn(resultPosition) {
46887
+ return this.resultsToArrayFormulas.get(resultPosition) || EMPTY_ARRAY;
46682
46888
  }
46683
- getArrayResultPositionIds(formulasPositionId) {
46684
- return this.arrayFormulasToResults.get(formulasPositionId) || EMPTY_ARRAY;
46889
+ getArrayResultPositions(formulasPosition) {
46890
+ return this.arrayFormulasToResults.get(formulasPosition) || EMPTY_ARRAY;
46685
46891
  }
46686
46892
  /**
46687
46893
  * Remove a node, also remove it from other nodes adjacency list
46688
46894
  */
46689
- removeNode(positionId) {
46690
- this.resultsToArrayFormulas.delete(positionId);
46691
- this.arrayFormulasToResults.delete(positionId);
46895
+ removeNode(position) {
46896
+ this.resultsToArrayFormulas.delete(position);
46897
+ this.arrayFormulasToResults.delete(position);
46692
46898
  }
46693
46899
  /**
46694
46900
  * Create a spreading relation between two cells
46695
46901
  */
46696
- addRelation({ arrayFormulaPositionId, resultPositionId, }) {
46697
- if (!this.resultsToArrayFormulas.has(resultPositionId)) {
46698
- this.resultsToArrayFormulas.set(resultPositionId, new Set());
46902
+ addRelation({ arrayFormulaPosition, resultPosition, }) {
46903
+ if (!this.resultsToArrayFormulas.has(resultPosition)) {
46904
+ this.resultsToArrayFormulas.set(resultPosition, this.createEmptyPositionSet());
46699
46905
  }
46700
- this.resultsToArrayFormulas.get(resultPositionId)?.add(arrayFormulaPositionId);
46701
- if (!this.arrayFormulasToResults.has(arrayFormulaPositionId)) {
46702
- this.arrayFormulasToResults.set(arrayFormulaPositionId, new Set());
46906
+ this.resultsToArrayFormulas.get(resultPosition)?.add(arrayFormulaPosition);
46907
+ if (!this.arrayFormulasToResults.has(arrayFormulaPosition)) {
46908
+ this.arrayFormulasToResults.set(arrayFormulaPosition, this.createEmptyPositionSet());
46703
46909
  }
46704
- this.arrayFormulasToResults.get(arrayFormulaPositionId)?.add(resultPositionId);
46910
+ this.arrayFormulasToResults.get(arrayFormulaPosition)?.add(resultPosition);
46705
46911
  }
46706
- hasArrayFormulaResult(positionId) {
46707
- return this.resultsToArrayFormulas.has(positionId);
46912
+ hasArrayFormulaResult(position) {
46913
+ return this.resultsToArrayFormulas.has(position);
46708
46914
  }
46709
- isArrayFormula(positionId) {
46710
- return this.arrayFormulasToResults.has(positionId);
46915
+ isArrayFormula(position) {
46916
+ return this.arrayFormulasToResults.has(position);
46711
46917
  }
46712
46918
  }
46713
46919
  const EMPTY_ARRAY = [];
@@ -46719,50 +46925,41 @@ class Evaluator {
46719
46925
  context;
46720
46926
  getters;
46721
46927
  compilationParams;
46722
- encoder = new PositionBitsEncoder();
46723
- evaluatedCells = new Map();
46724
- formulaDependencies = lazy(new FormulaDependencyGraph(this.encoder));
46725
- blockedArrayFormulas = new Set();
46726
- spreadingRelations = new SpreadingRelation();
46928
+ evaluatedCells = new PositionMap();
46929
+ formulaDependencies = lazy(new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this)));
46930
+ blockedArrayFormulas = new PositionSet({});
46931
+ spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
46727
46932
  constructor(context, getters) {
46728
46933
  this.context = context;
46729
46934
  this.getters = getters;
46730
46935
  this.compilationParams = buildCompilationParameters(this.context, this.getters, this.computeAndSave.bind(this));
46731
46936
  }
46732
46937
  getEvaluatedCell(position) {
46733
- return this.evaluatedCells.get(this.encoder.encode(position)) || EMPTY_CELL;
46938
+ return this.evaluatedCells.get(position) || EMPTY_CELL;
46734
46939
  }
46735
46940
  getSpreadPositionsOf(position) {
46736
- const positionId = this.encoder.encode(position);
46737
- if (!this.spreadingRelations.isArrayFormula(positionId)) {
46941
+ if (!this.spreadingRelations.isArrayFormula(position)) {
46738
46942
  return [];
46739
46943
  }
46740
- return Array.from(this.spreadingRelations.getArrayResultPositionIds(positionId)).map((positionId) => this.encoder.decode(positionId));
46741
- }
46742
- getArrayFormulaSpreadingOn(position) {
46743
- const positionId = this.encoder.encode(position);
46744
- const formulaPosition = this.getArrayFormulaSpreadingOnId(positionId);
46745
- return formulaPosition !== undefined ? this.encoder.decode(formulaPosition) : undefined;
46944
+ return Array.from(this.spreadingRelations.getArrayResultPositions(position));
46746
46945
  }
46747
46946
  getEvaluatedPositions() {
46748
- return [...this.evaluatedCells.keys()].map((p) => this.encoder.decode(p));
46947
+ return this.evaluatedCells.keys();
46749
46948
  }
46750
- getArrayFormulaSpreadingOnId(positionId) {
46751
- if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
46949
+ getArrayFormulaSpreadingOn(position) {
46950
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
46752
46951
  return undefined;
46753
46952
  }
46754
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
46755
- return Array.from(arrayFormulas).find((positionId) => !this.blockedArrayFormulas.has(positionId));
46953
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
46954
+ return Array.from(arrayFormulas).find((position) => !this.blockedArrayFormulas.has(position));
46756
46955
  }
46757
46956
  updateDependencies(position) {
46758
- const positionId = this.encoder.encode(position);
46759
- this.formulaDependencies().removeAllDependencies(positionId);
46760
- const dependencies = this.getDirectDependencies(positionId);
46761
- this.formulaDependencies().addDependencies(positionId, dependencies);
46957
+ this.formulaDependencies().removeAllDependencies(position);
46958
+ const dependencies = this.getDirectDependencies(position);
46959
+ this.formulaDependencies().addDependencies(position, dependencies);
46762
46960
  }
46763
46961
  addDependencies(position, dependencies) {
46764
- const positionId = this.encoder.encode(position);
46765
- this.formulaDependencies().addDependencies(positionId, dependencies);
46962
+ this.formulaDependencies().addDependencies(position, dependencies);
46766
46963
  }
46767
46964
  updateCompilationParameters() {
46768
46965
  // rebuild the compilation parameters (with a clean cache)
@@ -46770,47 +46967,57 @@ class Evaluator {
46770
46967
  this.compilationParams.evalContext.updateDependencies = this.updateDependencies.bind(this);
46771
46968
  this.compilationParams.evalContext.addDependencies = this.addDependencies.bind(this);
46772
46969
  }
46970
+ createEmptyPositionSet() {
46971
+ const sheetSizes = {};
46972
+ for (const sheetId of this.getters.getSheetIds()) {
46973
+ sheetSizes[sheetId] = {
46974
+ rows: this.getters.getNumberRows(sheetId),
46975
+ cols: this.getters.getNumberCols(sheetId),
46976
+ };
46977
+ }
46978
+ return new PositionSet(sheetSizes);
46979
+ }
46773
46980
  evaluateCells(positions) {
46774
- const cells = positions.map((p) => this.encoder.encode(p));
46775
- const cellsToCompute = new JetSet(cells);
46776
- const arrayFormulasPositionIds = this.getArrayFormulasImpactedByChangesOf(cells);
46777
- cellsToCompute.addMany(this.getCellsDependingOn(cells));
46778
- cellsToCompute.addMany(arrayFormulasPositionIds);
46779
- cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositionIds));
46981
+ const cellsToCompute = this.createEmptyPositionSet();
46982
+ cellsToCompute.addMany(positions);
46983
+ const arrayFormulasPositions = this.getArrayFormulasImpactedByChangesOf(positions);
46984
+ cellsToCompute.addMany(this.getCellsDependingOn(positions));
46985
+ cellsToCompute.addMany(arrayFormulasPositions);
46986
+ cellsToCompute.addMany(this.getCellsDependingOn(arrayFormulasPositions));
46780
46987
  this.evaluate(cellsToCompute);
46781
46988
  }
46782
- getArrayFormulasImpactedByChangesOf(positionIds) {
46783
- const impactedPositionIds = new JetSet();
46784
- for (const positionId of positionIds) {
46785
- const content = this.getCell(positionId)?.content;
46786
- const arrayFormulaPositionId = this.getArrayFormulaSpreadingOnId(positionId);
46787
- if (arrayFormulaPositionId !== undefined) {
46989
+ getArrayFormulasImpactedByChangesOf(positions) {
46990
+ const impactedPositions = this.createEmptyPositionSet();
46991
+ for (const position of positions) {
46992
+ const content = this.getters.getCell(position)?.content;
46993
+ const arrayFormulaPosition = this.getArrayFormulaSpreadingOn(position);
46994
+ if (arrayFormulaPosition !== undefined) {
46788
46995
  // take into account new collisions.
46789
- impactedPositionIds.add(arrayFormulaPositionId);
46996
+ impactedPositions.add(arrayFormulaPosition);
46790
46997
  }
46791
46998
  if (!content) {
46792
46999
  // The previous content could have blocked some array formulas
46793
- impactedPositionIds.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(positionId));
47000
+ impactedPositions.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(position));
46794
47001
  }
46795
47002
  }
46796
- return impactedPositionIds;
47003
+ return impactedPositions;
46797
47004
  }
46798
47005
  buildDependencyGraph() {
46799
- this.blockedArrayFormulas = new Set();
46800
- this.spreadingRelations = new SpreadingRelation();
47006
+ this.blockedArrayFormulas = this.createEmptyPositionSet();
47007
+ this.spreadingRelations = new SpreadingRelation(this.createEmptyPositionSet.bind(this));
46801
47008
  this.formulaDependencies = lazy(() => {
46802
- const dependencies = [...this.getAllCells()].flatMap((positionId) => this.getDirectDependencies(positionId).map((range) => ({
46803
- data: positionId,
47009
+ const dependencies = [...this.getAllCells()].flatMap((position) => this.getDirectDependencies(position).map((range) => ({
47010
+ data: position,
46804
47011
  boundingBox: {
46805
47012
  zone: range.zone,
46806
47013
  sheetId: range.sheetId,
46807
47014
  },
46808
47015
  })));
46809
- return new FormulaDependencyGraph(this.encoder, dependencies);
47016
+ return new FormulaDependencyGraph(this.createEmptyPositionSet.bind(this), dependencies);
46810
47017
  });
46811
47018
  }
46812
47019
  evaluateAllCells() {
46813
- this.evaluatedCells = new Map();
47020
+ this.evaluatedCells = new PositionMap();
46814
47021
  this.evaluate(this.getAllCells());
46815
47022
  }
46816
47023
  evaluateFormula(sheetId, formulaString) {
@@ -46827,57 +47034,50 @@ class Evaluator {
46827
47034
  return result.value;
46828
47035
  }
46829
47036
  getAllCells() {
46830
- const positionIds = new JetSet();
46831
- for (const sheetId of this.getters.getSheetIds()) {
46832
- const cellIds = this.getters.getCells(sheetId);
46833
- for (const cellId in cellIds) {
46834
- positionIds.add(this.encoder.encode(this.getters.getCellPosition(cellId)));
46835
- }
46836
- }
46837
- return positionIds;
47037
+ const positions = this.createEmptyPositionSet();
47038
+ positions.fillAllPositions();
47039
+ return positions;
46838
47040
  }
46839
- getArrayFormulasBlockedByOrSpreadingOn(positionId) {
46840
- if (!this.spreadingRelations.hasArrayFormulaResult(positionId)) {
47041
+ getArrayFormulasBlockedByOrSpreadingOn(position) {
47042
+ if (!this.spreadingRelations.hasArrayFormulaResult(position)) {
46841
47043
  return [];
46842
47044
  }
46843
- const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(positionId);
46844
- const cells = new JetSet(arrayFormulas);
46845
- cells.addMany(this.getCellsDependingOn(arrayFormulas));
46846
- return cells;
47045
+ const arrayFormulas = this.spreadingRelations.getFormulaPositionsSpreadingOn(position);
47046
+ const positions = this.createEmptyPositionSet();
47047
+ positions.addMany(arrayFormulas);
47048
+ positions.addMany(this.getCellsDependingOn(arrayFormulas));
47049
+ return positions;
46847
47050
  }
46848
- nextPositionsToUpdate = new JetSet();
47051
+ nextPositionsToUpdate = new PositionSet({});
46849
47052
  cellsBeingComputed = new Set();
46850
- evaluate(cells) {
47053
+ evaluate(positions) {
46851
47054
  this.cellsBeingComputed = new Set();
46852
- this.nextPositionsToUpdate = cells;
47055
+ this.nextPositionsToUpdate = positions;
46853
47056
  let currentIteration = 0;
46854
- while (this.nextPositionsToUpdate.size && currentIteration++ < MAX_ITERATION) {
47057
+ while (!this.nextPositionsToUpdate.isEmpty() && currentIteration++ < MAX_ITERATION) {
46855
47058
  this.updateCompilationParameters();
46856
- const positionIds = Array.from(this.nextPositionsToUpdate);
46857
- this.nextPositionsToUpdate.clear();
46858
- for (let i = 0; i < positionIds.length; ++i) {
46859
- const cell = positionIds[i];
46860
- this.evaluatedCells.delete(cell);
47059
+ const positions = this.nextPositionsToUpdate.clear();
47060
+ for (let i = 0; i < positions.length; ++i) {
47061
+ this.evaluatedCells.delete(positions[i]);
46861
47062
  }
46862
- for (let i = 0; i < positionIds.length; ++i) {
46863
- const cell = positionIds[i];
46864
- this.setEvaluatedCell(cell, this.computeCell(cell));
47063
+ for (let i = 0; i < positions.length; ++i) {
47064
+ const position = positions[i];
47065
+ const evaluatedCell = this.computeCell(position);
47066
+ if (evaluatedCell !== EMPTY_CELL) {
47067
+ this.evaluatedCells.set(position, evaluatedCell);
47068
+ }
46865
47069
  }
46866
47070
  }
46867
47071
  }
46868
- setEvaluatedCell(positionId, evaluatedCell) {
46869
- this.evaluatedCells.set(positionId, evaluatedCell);
46870
- }
46871
- computeCell(positionId) {
46872
- const evaluation = this.evaluatedCells.get(positionId);
47072
+ computeCell(position) {
47073
+ const evaluation = this.evaluatedCells.get(position);
46873
47074
  if (evaluation) {
46874
47075
  return evaluation; // already computed
46875
47076
  }
46876
- if (!this.blockedArrayFormulas.has(positionId)) {
46877
- this.invalidateSpreading(positionId);
47077
+ if (!this.blockedArrayFormulas.has(position)) {
47078
+ this.invalidateSpreading(position);
46878
47079
  }
46879
- const cellPosition = this.encoder.decode(positionId);
46880
- const cell = this.getters.getCell(cellPosition);
47080
+ const cell = this.getters.getCell(position);
46881
47081
  if (cell === undefined) {
46882
47082
  return EMPTY_CELL;
46883
47083
  }
@@ -46889,7 +47089,7 @@ class Evaluator {
46889
47089
  }
46890
47090
  this.cellsBeingComputed.add(cellId);
46891
47091
  return cell.isFormula
46892
- ? this.computeFormulaCell(cellPosition.sheetId, cell)
47092
+ ? this.computeFormulaCell(position.sheetId, cell)
46893
47093
  : evaluateLiteral(cell.content, localeFormat);
46894
47094
  }
46895
47095
  catch (e) {
@@ -46902,10 +47102,9 @@ class Evaluator {
46902
47102
  }
46903
47103
  }
46904
47104
  computeAndSave(position) {
46905
- const positionId = this.encoder.encode(position);
46906
- const evaluatedCell = this.computeCell(positionId);
46907
- if (!this.evaluatedCells.has(positionId)) {
46908
- this.setEvaluatedCell(positionId, evaluatedCell);
47105
+ const evaluatedCell = this.computeCell(position);
47106
+ if (!this.evaluatedCells.has(position)) {
47107
+ this.evaluatedCells.set(position, evaluatedCell);
46909
47108
  }
46910
47109
  return evaluatedCell;
46911
47110
  }
@@ -46943,24 +47142,23 @@ class Evaluator {
46943
47142
  throw new EvaluationError(_t("Result couldn't be automatically expanded. Please insert more columns and rows."));
46944
47143
  }
46945
47144
  updateSpreadRelation({ sheetId, col, row, }) {
46946
- const arrayFormulaPositionId = this.encoder.encode({ sheetId, col, row });
47145
+ const arrayFormulaPosition = { sheetId, col, row };
46947
47146
  return (i, j) => {
46948
47147
  const position = { sheetId, col: i + col, row: j + row };
46949
- const resultPositionId = this.encoder.encode(position);
46950
- this.spreadingRelations.addRelation({ resultPositionId, arrayFormulaPositionId });
47148
+ this.spreadingRelations.addRelation({ resultPosition: position, arrayFormulaPosition });
46951
47149
  };
46952
47150
  }
46953
- checkCollision({ sheetId, col, row }) {
46954
- const formulaPositionId = this.encoder.encode({ sheetId, col, row });
47151
+ checkCollision(formulaPosition) {
47152
+ const { sheetId, col, row } = formulaPosition;
46955
47153
  return (i, j) => {
46956
47154
  const position = { sheetId: sheetId, col: i + col, row: j + row };
46957
47155
  const rawCell = this.getters.getCell(position);
46958
47156
  if (rawCell?.content ||
46959
47157
  this.getters.getEvaluatedCell(position).type !== CellValueType.empty) {
46960
- this.blockedArrayFormulas.add(formulaPositionId);
47158
+ this.blockedArrayFormulas.add(formulaPosition);
46961
47159
  throw new EvaluationError(_t("Array result was not expanded because it would overwrite data in %s.", toXC(position.col, position.row)));
46962
47160
  }
46963
- this.blockedArrayFormulas.delete(formulaPositionId);
47161
+ this.blockedArrayFormulas.delete(formulaPosition);
46964
47162
  };
46965
47163
  }
46966
47164
  spreadValues({ sheetId, col, row }, matrixResult) {
@@ -46968,19 +47166,18 @@ class Evaluator {
46968
47166
  const position = { sheetId, col: i + col, row: j + row };
46969
47167
  const cell = this.getters.getCell(position);
46970
47168
  const evaluatedCell = createEvaluatedCell(nullValueToZeroValue(matrixResult[i][j]), this.getters.getLocale(), cell);
46971
- const positionId = this.encoder.encode(position);
46972
- this.setEvaluatedCell(positionId, evaluatedCell);
47169
+ this.evaluatedCells.set(position, evaluatedCell);
46973
47170
  // check if formula dependencies present in the spread zone
46974
47171
  // if so, they need to be recomputed
46975
- this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([positionId]));
47172
+ this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([position]));
46976
47173
  };
46977
47174
  }
46978
- invalidateSpreading(positionId) {
46979
- if (!this.spreadingRelations.isArrayFormula(positionId)) {
47175
+ invalidateSpreading(position) {
47176
+ if (!this.spreadingRelations.isArrayFormula(position)) {
46980
47177
  return;
46981
47178
  }
46982
- for (const child of this.spreadingRelations.getArrayResultPositionIds(positionId)) {
46983
- const content = this.getCell(child)?.content;
47179
+ for (const child of this.spreadingRelations.getArrayResultPositions(position)) {
47180
+ const content = this.getters.getCell(child)?.content;
46984
47181
  if (content) {
46985
47182
  // there's no point at re-evaluating overlapping array formulas,
46986
47183
  // there's still a collision
@@ -46990,28 +47187,25 @@ class Evaluator {
46990
47187
  this.nextPositionsToUpdate.addMany(this.getCellsDependingOn([child]));
46991
47188
  this.nextPositionsToUpdate.addMany(this.getArrayFormulasBlockedByOrSpreadingOn(child));
46992
47189
  }
46993
- this.spreadingRelations.removeNode(positionId);
47190
+ this.spreadingRelations.removeNode(position);
46994
47191
  }
46995
47192
  // ----------------------------------------------------------
46996
47193
  // COMMON FUNCTIONALITY
46997
47194
  // ----------------------------------------------------------
46998
- getDirectDependencies(positionId) {
46999
- const cell = this.getCell(positionId);
47195
+ getDirectDependencies(position) {
47196
+ const cell = this.getters.getCell(position);
47000
47197
  if (!cell?.isFormula) {
47001
47198
  return [];
47002
47199
  }
47003
47200
  return cell.compiledFormula.dependencies;
47004
47201
  }
47005
- getCellsDependingOn(positionIds) {
47202
+ getCellsDependingOn(positions) {
47006
47203
  const ranges = [];
47007
- for (const positionId of positionIds) {
47008
- ranges.push(this.encoder.decodeToBoundingBox(positionId));
47204
+ for (const position of positions) {
47205
+ ranges.push({ sheetId: position.sheetId, zone: positionToZone(position) });
47009
47206
  }
47010
47207
  return this.formulaDependencies().getCellsDependingOn(ranges);
47011
47208
  }
47012
- getCell(positionId) {
47013
- return this.getters.getCell(this.encoder.decode(positionId));
47014
- }
47015
47209
  }
47016
47210
  function forEachSpreadPositionInMatrix(nbColumns, nbRows, callback) {
47017
47211
  for (let i = 0; i < nbColumns; ++i) {
@@ -47037,85 +47231,6 @@ function nullValueToZeroValue(fPayload) {
47037
47231
  }
47038
47232
  return fPayload;
47039
47233
  }
47040
- /**
47041
- * Encode (and decode) cell positions { sheetId, col, row }
47042
- * to a single integer.
47043
- *
47044
- * `col` and `row` values are encoded on 21 bits each (max 2^21 = 2_097_152),
47045
- * An incremental integer id is assigned to each different sheet id, starting at 0.
47046
- *
47047
- * e.g.
47048
- * Given { col: 10, row: 4, sheetId: "abcde" }
47049
- * we have:
47050
- * - row "4" encoded on 21 bits: 000000000000000000100
47051
- * - col "10" encoded on 21 bits: 000000000000000001010
47052
- * - sheetId: let's say it's the 4th sheetId met, encoded to: 11
47053
- *
47054
- * The final encoded value is found by concatenating the 3 bit sequences:
47055
- *
47056
- * sheetId: 11
47057
- * col: 000000000000000001010
47058
- * row: 000000000000000000100
47059
- * => 11000000000000000001010000000000000000000100
47060
- *
47061
- * this binary sequence is the integer 13194160504836
47062
- */
47063
- class PositionBitsEncoder {
47064
- sheetMapping = {};
47065
- inverseSheetMapping = new Map();
47066
- constructor() {
47067
- try {
47068
- // @ts-ignore
47069
- o_spreadsheet.__DEBUG__ = o_spreadsheet.__DEBUG__ || {};
47070
- // @ts-ignore
47071
- o_spreadsheet.__DEBUG__.decodePosition = this.decode.bind(this);
47072
- // @ts-ignore
47073
- o_spreadsheet.__DEBUG__.encodePosition = this.encode.bind(this);
47074
- }
47075
- catch (error) { }
47076
- }
47077
- /**
47078
- * Encode a cell position to a single integer.
47079
- */
47080
- encode({ sheetId, col, row }) {
47081
- return (this.encodeSheet(sheetId) << 42n) | (BigInt(col) << 21n) | BigInt(row);
47082
- }
47083
- encodeBoundingBox({ sheetId, zone }) {
47084
- const positions = [];
47085
- forEachPositionsInZone(zone, (col, row) => {
47086
- positions.push(this.encode({ sheetId, col, row }));
47087
- });
47088
- return positions;
47089
- }
47090
- decode(id) {
47091
- // keep only the last 21 bits by AND-ing the bit sequence with 21 ones
47092
- const row = Number(id & 2097151n);
47093
- const col = Number((id >> 21n) & 2097151n);
47094
- const sheetId = this.decodeSheet(id >> 42n);
47095
- return { sheetId, col, row };
47096
- }
47097
- decodeToBoundingBox(id) {
47098
- const { sheetId, col, row } = this.decode(id);
47099
- return { sheetId, zone: { left: col, top: row, right: col, bottom: row } };
47100
- }
47101
- encodeSheet(sheetId) {
47102
- const sheetKey = this.sheetMapping[sheetId];
47103
- if (sheetKey === undefined) {
47104
- const newSheetKey = BigInt(Object.keys(this.sheetMapping).length);
47105
- this.sheetMapping[sheetId] = newSheetKey;
47106
- this.inverseSheetMapping.set(newSheetKey, sheetId);
47107
- return newSheetKey;
47108
- }
47109
- return sheetKey;
47110
- }
47111
- decodeSheet(sheetKey) {
47112
- const sheetId = this.inverseSheetMapping.get(sheetKey);
47113
- if (sheetId === undefined) {
47114
- throw new Error("Sheet id not found");
47115
- }
47116
- return sheetId;
47117
- }
47118
- }
47119
47234
  function updateEvalContextAndExecute(compiledFormula, compilationParams, sheetId, cellId) {
47120
47235
  compilationParams.evalContext.__originCellXC = lazy(() => {
47121
47236
  if (!cellId) {
@@ -47262,6 +47377,10 @@ class EvaluationPlugin extends UIPlugin {
47262
47377
  this.evaluator.updateDependencies(cmd);
47263
47378
  }
47264
47379
  break;
47380
+ case "DUPLICATE_SHEET":
47381
+ case "CREATE_SHEET":
47382
+ this.shouldRebuildDependenciesGraph = true;
47383
+ break;
47265
47384
  case "EVALUATE_CELLS":
47266
47385
  this.evaluator.evaluateAllCells();
47267
47386
  break;
@@ -60005,6 +60124,6 @@ const constants = {
60005
60124
  export { AbstractCellClipboardHandler, AbstractChart, AbstractFigureClipboardHandler, CellErrorType, CommandResult, CorePlugin, DispatchResult, EvaluationError, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, __info__, addFunction, addRenderingLayer, astToFormula, compile, compileTokens, components, constants, convertAstNodes, coreTypes, findCellInNewZone, functionCache, helpers, hooks, invalidateCFEvaluationCommands, invalidateDependenciesCommands, invalidateEvaluationCommands, iterateAstNodes, links, load, parse, parseTokens, readonlyAllowedCommands, registries, setDefaultSheetViewSize, setTranslationMethod, stores, tokenColors, tokenize };
60006
60125
 
60007
60126
 
60008
- __info__.version = "17.2.0-alpha.8";
60009
- __info__.date = "2024-03-15T11:01:01.388Z";
60010
- __info__.hash = "11cf381";
60127
+ __info__.version = "17.2.0";
60128
+ __info__.date = "2024-03-20T08:12:44.398Z";
60129
+ __info__.hash = "1869c24";