@odoo/o-spreadsheet 15.2.12 → 15.2.14

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.
@@ -108,14 +108,72 @@ const FORMULA_REF_IDENTIFIER = "|";
108
108
  // -----------------------------------------------------------------------------
109
109
  // Date Type
110
110
  // -----------------------------------------------------------------------------
111
+ /**
112
+ * A DateTime object that can be used to manipulate spreadsheet dates.
113
+ * Conceptually, a spreadsheet date is simply a number with a date format,
114
+ * and it is timezone-agnostic.
115
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
116
+ */
117
+ class DateTime {
118
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
119
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
120
+ }
121
+ static fromTimestamp(timestamp) {
122
+ const date = new Date(timestamp);
123
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
124
+ }
125
+ static now() {
126
+ const now = new Date();
127
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
128
+ }
129
+ toString() {
130
+ return this.jsDate.toString();
131
+ }
132
+ getTime() {
133
+ return this.jsDate.getTime();
134
+ }
135
+ getFullYear() {
136
+ return this.jsDate.getUTCFullYear();
137
+ }
138
+ getMonth() {
139
+ return this.jsDate.getUTCMonth();
140
+ }
141
+ getDate() {
142
+ return this.jsDate.getUTCDate();
143
+ }
144
+ getDay() {
145
+ return this.jsDate.getUTCDay();
146
+ }
147
+ getHours() {
148
+ return this.jsDate.getUTCHours();
149
+ }
150
+ getMinutes() {
151
+ return this.jsDate.getUTCMinutes();
152
+ }
153
+ getSeconds() {
154
+ return this.jsDate.getUTCSeconds();
155
+ }
156
+ setDate(date) {
157
+ this.jsDate.setUTCDate(date);
158
+ }
159
+ setHours(hours) {
160
+ this.jsDate.setUTCHours(hours);
161
+ }
162
+ setMinutes(minutes) {
163
+ this.jsDate.setUTCMinutes(minutes);
164
+ }
165
+ setSeconds(seconds) {
166
+ this.jsDate.setUTCSeconds(seconds);
167
+ }
168
+ }
111
169
  // -----------------------------------------------------------------------------
112
170
  // Parsing
113
171
  // -----------------------------------------------------------------------------
114
172
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
115
- const CURRENT_YEAR = new Date().getFullYear();
116
- const INITIAL_1900_DAY$1 = new Date(1899, 11, 30);
117
- const INITIAL_JS_DAY = new Date(0);
118
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY$1;
173
+ const CURRENT_YEAR = DateTime.now().getFullYear();
174
+ const INITIAL_1900_DAY$1 = new DateTime(1899, 11, 30);
175
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
176
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY$1.getTime();
119
177
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
120
178
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
121
179
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -155,7 +213,7 @@ function parseDateTime(str) {
155
213
  return {
156
214
  value: date.value + time.value,
157
215
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
158
- jsDate: new Date(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
216
+ jsDate: new DateTime(date.jsDate.getFullYear() + time.jsDate.getFullYear() - 1899, date.jsDate.getMonth() + time.jsDate.getMonth() - 11, date.jsDate.getDate() + time.jsDate.getDate() - 30, date.jsDate.getHours() + time.jsDate.getHours(), date.jsDate.getMinutes() + time.jsDate.getMinutes(), date.jsDate.getSeconds() + time.jsDate.getSeconds()),
159
217
  };
160
218
  }
161
219
  return date || time;
@@ -172,13 +230,13 @@ function parseDate(str, dateFormat) {
172
230
  const day = Number(parts[dayIndex]);
173
231
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
174
232
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
175
- const jsDate = new Date(year, month - 1, day);
233
+ const jsDate = new DateTime(year, month - 1, day);
176
234
  const sep = str.match(/\/|-|\s/)[0];
177
235
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
178
236
  // invalid date
179
237
  return null;
180
238
  }
181
- const delta = jsDate - INITIAL_1900_DAY$1;
239
+ const delta = jsDate.getTime() - INITIAL_1900_DAY$1.getTime();
182
240
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
183
241
  if (parts[yearIndex]) {
184
242
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -238,7 +296,7 @@ function parseTime(str) {
238
296
  if (hours >= 24) {
239
297
  format = "hhhh:mm:ss";
240
298
  }
241
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
299
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
242
300
  return {
243
301
  value: hours / 24 + minutes / 1440 + seconds / 86400,
244
302
  format: format,
@@ -252,7 +310,7 @@ function parseTime(str) {
252
310
  // -----------------------------------------------------------------------------
253
311
  function numberToJsDate(value) {
254
312
  const truncValue = Math.trunc(value);
255
- let date = new Date(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
313
+ let date = DateTime.fromTimestamp(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
256
314
  let time = value - truncValue;
257
315
  time = time < 0 ? 1 + time : time;
258
316
  const hours = Math.round(time * 24);
@@ -325,7 +383,7 @@ function formatJSTime(jsDate, format) {
325
383
  .map((p) => {
326
384
  switch (p) {
327
385
  case "hhhh":
328
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1) / (60 * 60 * 1000));
386
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1.getTime()) / (60 * 60 * 1000));
329
387
  return helapsedHours.toString();
330
388
  case "hh":
331
389
  return hours.toString().padStart(2, "0");
@@ -2686,13 +2744,6 @@ for (let font of fontSizes) {
2686
2744
  }
2687
2745
 
2688
2746
  //------------------------------------------------------------------------------
2689
- /**
2690
- * Stringify an object, like JSON.stringify, except that the first level of keys
2691
- * is ordered.
2692
- */
2693
- function stringify(obj) {
2694
- return JSON.stringify(obj, Object.keys(obj).sort());
2695
- }
2696
2747
  /**
2697
2748
  * Remove quotes from a quoted string
2698
2749
  * ```js
@@ -2851,7 +2902,7 @@ function isBoolean(str) {
2851
2902
  function isDateTime(str) {
2852
2903
  return parseDateTime(str) !== null;
2853
2904
  }
2854
- const MARKDOWN_LINK_REGEX = /^\[([^\[]+)\]\((.+)\)$/;
2905
+ const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
2855
2906
  //link must start with http or https
2856
2907
  //https://stackoverflow.com/a/3809435/4760614
2857
2908
  const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
@@ -2917,7 +2968,7 @@ const DEBUG = {};
2917
2968
  */
2918
2969
  function getItemId(item, itemsDic) {
2919
2970
  for (let [key, value] of Object.entries(itemsDic)) {
2920
- if (stringify(value) === stringify(item)) {
2971
+ if (deepEquals(value, item)) {
2921
2972
  return parseInt(key, 10);
2922
2973
  }
2923
2974
  }
@@ -4727,7 +4778,7 @@ var database = /*#__PURE__*/Object.freeze({
4727
4778
  DVARP: DVARP
4728
4779
  });
4729
4780
 
4730
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
4781
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
4731
4782
  const DEFAULT_TYPE = 1;
4732
4783
  const DEFAULT_WEEKEND = 1;
4733
4784
  function isLeapYear(year) {
@@ -4756,7 +4807,7 @@ const DATE = {
4756
4807
  if (_year < 1900) {
4757
4808
  _year += 1900;
4758
4809
  }
4759
- const jsDate = new Date(_year, _month - 1, _day);
4810
+ const jsDate = new DateTime(_year, _month - 1, _day);
4760
4811
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4761
4812
  assert(() => delta >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
4762
4813
  return Math.round(delta / 86400000);
@@ -4829,7 +4880,7 @@ const EDATE = {
4829
4880
  const yStart = _startDate.getFullYear();
4830
4881
  const mStart = _startDate.getMonth();
4831
4882
  const dStart = _startDate.getDate();
4832
- const jsDate = new Date(yStart, mStart + _months, dStart);
4883
+ const jsDate = new DateTime(yStart, mStart + _months, dStart);
4833
4884
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4834
4885
  return Math.round(delta / 86400000);
4835
4886
  },
@@ -4851,7 +4902,7 @@ const EOMONTH = {
4851
4902
  const _months = Math.trunc(toNumber(months));
4852
4903
  const yStart = _startDate.getFullYear();
4853
4904
  const mStart = _startDate.getMonth();
4854
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
4905
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
4855
4906
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4856
4907
  return Math.round(delta / 86400000);
4857
4908
  },
@@ -4891,17 +4942,17 @@ const ISOWEEKNUM = {
4891
4942
  // The first week of the year is the week that contains the first
4892
4943
  // Thursday of the year.
4893
4944
  let firstThursday = 1;
4894
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
4945
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
4895
4946
  firstThursday += 1;
4896
4947
  }
4897
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
4948
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
4898
4949
  // The last week of the year is the week that contains the last Thursday of
4899
4950
  // the year.
4900
4951
  let lastThursday = 31;
4901
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
4952
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
4902
4953
  lastThursday -= 1;
4903
4954
  }
4904
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
4955
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
4905
4956
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
4906
4957
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
4907
4958
  let offsetYear;
@@ -4927,17 +4978,17 @@ const ISOWEEKNUM = {
4927
4978
  case 1:
4928
4979
  // firstDay is the 1st day of the 1st week of the year after
4929
4980
  // firstDay = lastDayOfLastWeek + 1 Day
4930
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
4981
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
4931
4982
  break;
4932
4983
  case -1:
4933
4984
  // firstDay is the 1st day of the 1st week of the previous year.
4934
4985
  // The first week of the previous year is the week that contains the
4935
4986
  // first Thursday of the previous year.
4936
4987
  let firstThursdayPreviousYear = 1;
4937
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4988
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4938
4989
  firstThursdayPreviousYear += 1;
4939
4990
  }
4940
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
4991
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
4941
4992
  break;
4942
4993
  }
4943
4994
  const dif = (_date.getTime() - firstDay.getTime()) / 86400000;
@@ -5076,8 +5127,8 @@ const NETWORKDAYS_INTL = {
5076
5127
  });
5077
5128
  }
5078
5129
  const invertDate = _startDate.getTime() > _endDate.getTime();
5079
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
5080
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
5130
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
5131
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
5081
5132
  const timeStopDate = stopDate.getTime();
5082
5133
  let timeStepDate = stepDate.getTime();
5083
5134
  let netWorkingDay = 0;
@@ -5101,8 +5152,7 @@ const NOW = {
5101
5152
  returns: ["DATE"],
5102
5153
  returnFormat: { specificFormat: "m/d/yyyy hh:mm:ss" },
5103
5154
  compute: function () {
5104
- let today = new Date();
5105
- today.setMilliseconds(0);
5155
+ let today = DateTime.now();
5106
5156
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
5107
5157
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
5108
5158
  return Math.floor(delta / 86400000) + time;
@@ -5176,8 +5226,8 @@ const TODAY = {
5176
5226
  returns: ["DATE"],
5177
5227
  returnFormat: { specificFormat: "m/d/yyyy" },
5178
5228
  compute: function () {
5179
- const today = new Date();
5180
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
5229
+ const today = DateTime.now();
5230
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
5181
5231
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
5182
5232
  return Math.round(delta / 86400000);
5183
5233
  },
@@ -5233,10 +5283,10 @@ const WEEKNUM = {
5233
5283
  }
5234
5284
  const y = _date.getFullYear();
5235
5285
  let dayStart = 1;
5236
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
5286
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5237
5287
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
5238
5288
  dayStart += 1;
5239
- startDayOfFirstWeek = new Date(y, 0, dayStart);
5289
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5240
5290
  }
5241
5291
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / 86400000;
5242
5292
  if (dif < 0) {
@@ -5290,7 +5340,7 @@ const WORKDAY_INTL = {
5290
5340
  timesHoliday.add(holiday.getTime());
5291
5341
  });
5292
5342
  }
5293
- let stepDate = new Date(_startDate.getTime());
5343
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
5294
5344
  let timeStepDate = stepDate.getTime();
5295
5345
  const unitDay = Math.sign(_numDays);
5296
5346
  let stepDay = Math.abs(_numDays);
@@ -9382,7 +9432,7 @@ class BordersPlugin extends CorePlugin {
9382
9432
  */
9383
9433
  function getBorderId(border) {
9384
9434
  for (let [key, value] of Object.entries(borders)) {
9385
- if (stringify(value) === stringify(border)) {
9435
+ if (deepEquals(value, border)) {
9386
9436
  return parseInt(key, 10);
9387
9437
  }
9388
9438
  }
@@ -9620,12 +9670,10 @@ class CellPlugin extends CorePlugin {
9620
9670
  * starting an async evaluation even if it has been moved or re-allocated
9621
9671
  */
9622
9672
  getCellById(cellId) {
9623
- for (const sheet of Object.values(this.cells)) {
9624
- if (sheet[cellId]) {
9625
- return sheet[cellId];
9626
- }
9627
- }
9628
- return undefined;
9673
+ // this must be as fast as possible
9674
+ const position = this.getters.getCellPosition(cellId);
9675
+ const sheet = this.cells[position.sheetId];
9676
+ return sheet[cellId];
9629
9677
  }
9630
9678
  /**
9631
9679
  * Try to infer the cell format based on the formula dependencies.
@@ -23390,9 +23438,9 @@ function revertChanges(revisions) {
23390
23438
  * Apply the changes of the given HistoryChange to the state
23391
23439
  */
23392
23440
  function applyChange(change, target) {
23393
- let val = change.root;
23394
- let key = change.path[change.path.length - 1];
23395
- for (let pathIndex = 0; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23441
+ let val = change.path[0];
23442
+ const key = change.path[change.path.length - 1];
23443
+ for (let pathIndex = 1; pathIndex < change.path.slice(0, -1).length; pathIndex++) {
23396
23444
  const p = change.path[pathIndex];
23397
23445
  if (val[p] === undefined) {
23398
23446
  const nextPath = change.path[pathIndex + 1];
@@ -23848,13 +23896,14 @@ class StateObserver {
23848
23896
  }
23849
23897
  addChange(...args) {
23850
23898
  const val = args.pop();
23851
- const [root, ...path] = args;
23899
+ const root = args[0];
23852
23900
  let value = root;
23853
- let key = path[path.length - 1];
23854
- for (let pathIndex = 0; pathIndex <= path.length - 2; pathIndex++) {
23855
- const p = path[pathIndex];
23901
+ let key = args[args.length - 1];
23902
+ const pathLength = args.length - 2;
23903
+ for (let pathIndex = 1; pathIndex <= pathLength; pathIndex++) {
23904
+ const p = args[pathIndex];
23856
23905
  if (value[p] === undefined) {
23857
- const nextPath = path[pathIndex + 1];
23906
+ const nextPath = args[pathIndex + 1];
23858
23907
  value[p] = createEmptyStructure(nextPath);
23859
23908
  }
23860
23909
  value = value[p];
@@ -23863,8 +23912,7 @@ class StateObserver {
23863
23912
  return;
23864
23913
  }
23865
23914
  this.changes.push({
23866
- root,
23867
- path,
23915
+ path: args,
23868
23916
  before: value[key],
23869
23917
  after: val,
23870
23918
  });
@@ -25904,7 +25952,10 @@ class Model extends owl.core.EventBus {
25904
25952
  */
25905
25953
  checkDispatchAllowed(command) {
25906
25954
  const results = this.handlers.map((handler) => handler.allowDispatch(command));
25907
- return new DispatchResult(results.flat());
25955
+ if (results.some((r) => r !== 0 /* Success */)) {
25956
+ return new DispatchResult(results.flat());
25957
+ }
25958
+ return DispatchResult.Success;
25908
25959
  }
25909
25960
  finalize() {
25910
25961
  this.status = 3 /* Finalizing */;
@@ -31343,6 +31394,6 @@ const helpers = {
31343
31394
  export { CommandResult, CorePlugin, DATETIME_FORMAT, DataSource, DispatchResult, Model, Registry, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, DEBUG as __DEBUG__, __info__, astToFormula, cellTypes, compile, convertAstNodes, coreTypes, functionCache, helpers, invalidateEvaluationCommands, parse, readonlyAllowedCommands, registries, setTranslationMethod };
31344
31395
 
31345
31396
 
31346
- __info__.version = '15.2.12';
31347
- __info__.date = '2023-11-16T11:57:04.728Z';
31348
- __info__.hash = 'd0fd7c1';
31397
+ __info__.version = '15.2.14';
31398
+ __info__.date = '2024-01-12T13:37:05.872Z';
31399
+ __info__.hash = '6515f7c';