@odoo/o-spreadsheet 15.0.14 → 15.0.16

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.
@@ -106,14 +106,72 @@ const FORMULA_REF_IDENTIFIER = "|";
106
106
  // -----------------------------------------------------------------------------
107
107
  // Date Type
108
108
  // -----------------------------------------------------------------------------
109
+ /**
110
+ * A DateTime object that can be used to manipulate spreadsheet dates.
111
+ * Conceptually, a spreadsheet date is simply a number with a date format,
112
+ * and it is timezone-agnostic.
113
+ * This DateTime object consistently uses UTC time to represent a naive date and time.
114
+ */
115
+ class DateTime {
116
+ constructor(year, month, day, hours = 0, minutes = 0, seconds = 0) {
117
+ this.jsDate = new Date(Date.UTC(year, month, day, hours, minutes, seconds, 0));
118
+ }
119
+ static fromTimestamp(timestamp) {
120
+ const date = new Date(timestamp);
121
+ return new DateTime(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds());
122
+ }
123
+ static now() {
124
+ const now = new Date();
125
+ return new DateTime(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds());
126
+ }
127
+ toString() {
128
+ return this.jsDate.toString();
129
+ }
130
+ getTime() {
131
+ return this.jsDate.getTime();
132
+ }
133
+ getFullYear() {
134
+ return this.jsDate.getUTCFullYear();
135
+ }
136
+ getMonth() {
137
+ return this.jsDate.getUTCMonth();
138
+ }
139
+ getDate() {
140
+ return this.jsDate.getUTCDate();
141
+ }
142
+ getDay() {
143
+ return this.jsDate.getUTCDay();
144
+ }
145
+ getHours() {
146
+ return this.jsDate.getUTCHours();
147
+ }
148
+ getMinutes() {
149
+ return this.jsDate.getUTCMinutes();
150
+ }
151
+ getSeconds() {
152
+ return this.jsDate.getUTCSeconds();
153
+ }
154
+ setDate(date) {
155
+ this.jsDate.setUTCDate(date);
156
+ }
157
+ setHours(hours) {
158
+ this.jsDate.setUTCHours(hours);
159
+ }
160
+ setMinutes(minutes) {
161
+ this.jsDate.setUTCMinutes(minutes);
162
+ }
163
+ setSeconds(seconds) {
164
+ this.jsDate.setUTCSeconds(seconds);
165
+ }
166
+ }
109
167
  // -----------------------------------------------------------------------------
110
168
  // Parsing
111
169
  // -----------------------------------------------------------------------------
112
170
  const CURRENT_MILLENIAL = 2000; // note: don't forget to update this in 2999
113
- const CURRENT_YEAR = new Date().getFullYear();
114
- const INITIAL_1900_DAY$1 = new Date(1899, 11, 30);
115
- const INITIAL_JS_DAY = new Date(0);
116
- const DATE_JS_1900_OFFSET = INITIAL_JS_DAY - INITIAL_1900_DAY$1;
171
+ const CURRENT_YEAR = DateTime.now().getFullYear();
172
+ const INITIAL_1900_DAY$1 = new DateTime(1899, 11, 30);
173
+ const INITIAL_JS_DAY = DateTime.fromTimestamp(0);
174
+ const DATE_JS_1900_OFFSET = INITIAL_JS_DAY.getTime() - INITIAL_1900_DAY$1.getTime();
117
175
  const mdyDateRegexp = /^\d{1,2}(\/|-|\s)\d{1,2}((\/|-|\s)\d{1,4})?$/;
118
176
  const ymdDateRegexp = /^\d{3,4}(\/|-|\s)\d{1,2}(\/|-|\s)\d{1,2}$/;
119
177
  const timeRegexp = /((\d+(:\d+)?(:\d+)?\s*(AM|PM))|(\d+:\d+(:\d+)?))$/;
@@ -153,7 +211,7 @@ function parseDateTime(str) {
153
211
  return {
154
212
  value: date.value + time.value,
155
213
  format: date.format + " " + (time.format === "hhhh:mm:ss" ? "hh:mm:ss" : time.format),
156
- 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()),
214
+ 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()),
157
215
  };
158
216
  }
159
217
  return date || time;
@@ -170,13 +228,13 @@ function parseDate(str, dateFormat) {
170
228
  const day = Number(parts[dayIndex]);
171
229
  const leadingZero = (parts[monthIndex].length === 2 && month < 10) || (parts[dayIndex].length === 2 && day < 10);
172
230
  const year = parts[yearIndex] ? inferYear(parts[yearIndex]) : CURRENT_YEAR;
173
- const jsDate = new Date(year, month - 1, day);
231
+ const jsDate = new DateTime(year, month - 1, day);
174
232
  const sep = str.match(/\/|-|\s/)[0];
175
233
  if (jsDate.getMonth() !== month - 1 || jsDate.getDate() !== day) {
176
234
  // invalid date
177
235
  return null;
178
236
  }
179
- const delta = jsDate - INITIAL_1900_DAY$1;
237
+ const delta = jsDate.getTime() - INITIAL_1900_DAY$1.getTime();
180
238
  let format = leadingZero ? `mm${sep}dd` : `m${sep}d`;
181
239
  if (parts[yearIndex]) {
182
240
  format = isMDY ? format + sep + "yyyy" : "yyyy" + sep + format;
@@ -236,7 +294,7 @@ function parseTime(str) {
236
294
  if (hours >= 24) {
237
295
  format = "hhhh:mm:ss";
238
296
  }
239
- const jsDate = new Date(1899, 11, 30, hours, minutes, seconds);
297
+ const jsDate = new DateTime(1899, 11, 30, hours, minutes, seconds);
240
298
  return {
241
299
  value: hours / 24 + minutes / 1440 + seconds / 86400,
242
300
  format: format,
@@ -250,7 +308,7 @@ function parseTime(str) {
250
308
  // -----------------------------------------------------------------------------
251
309
  function numberToJsDate(value) {
252
310
  const truncValue = Math.trunc(value);
253
- let date = new Date(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
311
+ let date = DateTime.fromTimestamp(truncValue * 86400 * 1000 - DATE_JS_1900_OFFSET);
254
312
  let time = value - truncValue;
255
313
  time = time < 0 ? 1 + time : time;
256
314
  const hours = Math.round(time * 24);
@@ -323,7 +381,7 @@ function formatJSTime(jsDate, format) {
323
381
  .map((p) => {
324
382
  switch (p) {
325
383
  case "hhhh":
326
- const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1) / (60 * 60 * 1000));
384
+ const helapsedHours = Math.floor((jsDate.getTime() - INITIAL_1900_DAY$1.getTime()) / (60 * 60 * 1000));
327
385
  return helapsedHours.toString();
328
386
  case "hh":
329
387
  return hours.toString().padStart(2, "0");
@@ -2823,7 +2881,7 @@ function isBoolean(str) {
2823
2881
  function isDateTime(str) {
2824
2882
  return parseDateTime(str) !== null;
2825
2883
  }
2826
- const MARKDOWN_LINK_REGEX = /^\[([^\[]+)\]\((.+)\)$/;
2884
+ const MARKDOWN_LINK_REGEX = /^\[(.+)\]\((.+)\)$/;
2827
2885
  //link must start with http or https
2828
2886
  //https://stackoverflow.com/a/3809435/4760614
2829
2887
  const WEB_LINK_REGEX = /^https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,4}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)$/;
@@ -4726,7 +4784,7 @@ var database = /*#__PURE__*/Object.freeze({
4726
4784
  DVARP: DVARP
4727
4785
  });
4728
4786
 
4729
- const INITIAL_1900_DAY = new Date(1899, 11, 30);
4787
+ const INITIAL_1900_DAY = new DateTime(1899, 11, 30);
4730
4788
  const DEFAULT_TYPE = 1;
4731
4789
  const DEFAULT_WEEKEND = 1;
4732
4790
  function isLeapYear(year) {
@@ -4755,7 +4813,7 @@ const DATE = {
4755
4813
  if (_year < 1900) {
4756
4814
  _year += 1900;
4757
4815
  }
4758
- const jsDate = new Date(_year, _month - 1, _day);
4816
+ const jsDate = new DateTime(_year, _month - 1, _day);
4759
4817
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4760
4818
  assert(() => delta >= 0, _lt(`The function [[FUNCTION_NAME]] result must be greater than or equal 01/01/1900.`));
4761
4819
  return Math.round(delta / 86400000);
@@ -4828,7 +4886,7 @@ const EDATE = {
4828
4886
  const yStart = _startDate.getFullYear();
4829
4887
  const mStart = _startDate.getMonth();
4830
4888
  const dStart = _startDate.getDate();
4831
- const jsDate = new Date(yStart, mStart + _months, dStart);
4889
+ const jsDate = new DateTime(yStart, mStart + _months, dStart);
4832
4890
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4833
4891
  return Math.round(delta / 86400000);
4834
4892
  },
@@ -4850,7 +4908,7 @@ const EOMONTH = {
4850
4908
  const _months = Math.trunc(toNumber(months));
4851
4909
  const yStart = _startDate.getFullYear();
4852
4910
  const mStart = _startDate.getMonth();
4853
- const jsDate = new Date(yStart, mStart + _months + 1, 0);
4911
+ const jsDate = new DateTime(yStart, mStart + _months + 1, 0);
4854
4912
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
4855
4913
  return Math.round(delta / 86400000);
4856
4914
  },
@@ -4890,17 +4948,17 @@ const ISOWEEKNUM = {
4890
4948
  // The first week of the year is the week that contains the first
4891
4949
  // Thursday of the year.
4892
4950
  let firstThursday = 1;
4893
- while (new Date(y, 0, firstThursday).getDay() !== 4) {
4951
+ while (new DateTime(y, 0, firstThursday).getDay() !== 4) {
4894
4952
  firstThursday += 1;
4895
4953
  }
4896
- const firstDayOfFirstWeek = new Date(y, 0, firstThursday - 3);
4954
+ const firstDayOfFirstWeek = new DateTime(y, 0, firstThursday - 3);
4897
4955
  // The last week of the year is the week that contains the last Thursday of
4898
4956
  // the year.
4899
4957
  let lastThursday = 31;
4900
- while (new Date(y, 11, lastThursday).getDay() !== 4) {
4958
+ while (new DateTime(y, 11, lastThursday).getDay() !== 4) {
4901
4959
  lastThursday -= 1;
4902
4960
  }
4903
- const lastDayOfLastWeek = new Date(y, 11, lastThursday + 3);
4961
+ const lastDayOfLastWeek = new DateTime(y, 11, lastThursday + 3);
4904
4962
  // B - If our date > lastDayOfLastWeek then it's in the weeks of the year after
4905
4963
  // If our date < firstDayOfFirstWeek then it's in the weeks of the year before
4906
4964
  let offsetYear;
@@ -4926,17 +4984,17 @@ const ISOWEEKNUM = {
4926
4984
  case 1:
4927
4985
  // firstDay is the 1st day of the 1st week of the year after
4928
4986
  // firstDay = lastDayOfLastWeek + 1 Day
4929
- firstDay = new Date(y, 11, lastThursday + 3 + 1);
4987
+ firstDay = new DateTime(y, 11, lastThursday + 3 + 1);
4930
4988
  break;
4931
4989
  case -1:
4932
4990
  // firstDay is the 1st day of the 1st week of the previous year.
4933
4991
  // The first week of the previous year is the week that contains the
4934
4992
  // first Thursday of the previous year.
4935
4993
  let firstThursdayPreviousYear = 1;
4936
- while (new Date(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4994
+ while (new DateTime(y - 1, 0, firstThursdayPreviousYear).getDay() !== 4) {
4937
4995
  firstThursdayPreviousYear += 1;
4938
4996
  }
4939
- firstDay = new Date(y - 1, 0, firstThursdayPreviousYear - 3);
4997
+ firstDay = new DateTime(y - 1, 0, firstThursdayPreviousYear - 3);
4940
4998
  break;
4941
4999
  }
4942
5000
  const dif = (_date.getTime() - firstDay.getTime()) / 86400000;
@@ -5075,8 +5133,8 @@ const NETWORKDAYS_INTL = {
5075
5133
  });
5076
5134
  }
5077
5135
  const invertDate = _startDate.getTime() > _endDate.getTime();
5078
- const stopDate = new Date((invertDate ? _startDate : _endDate).getTime());
5079
- let stepDate = new Date((invertDate ? _endDate : _startDate).getTime());
5136
+ const stopDate = DateTime.fromTimestamp((invertDate ? _startDate : _endDate).getTime());
5137
+ let stepDate = DateTime.fromTimestamp((invertDate ? _endDate : _startDate).getTime());
5080
5138
  const timeStopDate = stopDate.getTime();
5081
5139
  let timeStepDate = stepDate.getTime();
5082
5140
  let netWorkingDay = 0;
@@ -5100,8 +5158,7 @@ const NOW = {
5100
5158
  returns: ["DATE"],
5101
5159
  returnFormat: { specificFormat: "m/d/yyyy hh:mm:ss" },
5102
5160
  compute: function () {
5103
- let today = new Date();
5104
- today.setMilliseconds(0);
5161
+ let today = DateTime.now();
5105
5162
  const delta = today.getTime() - INITIAL_1900_DAY.getTime();
5106
5163
  const time = today.getHours() / 24 + today.getMinutes() / 1440 + today.getSeconds() / 86400;
5107
5164
  return Math.floor(delta / 86400000) + time;
@@ -5175,8 +5232,8 @@ const TODAY = {
5175
5232
  returns: ["DATE"],
5176
5233
  returnFormat: { specificFormat: "m/d/yyyy" },
5177
5234
  compute: function () {
5178
- const today = new Date();
5179
- const jsDate = new Date(today.getFullYear(), today.getMonth(), today.getDate());
5235
+ const today = DateTime.now();
5236
+ const jsDate = new DateTime(today.getFullYear(), today.getMonth(), today.getDate());
5180
5237
  const delta = jsDate.getTime() - INITIAL_1900_DAY.getTime();
5181
5238
  return Math.round(delta / 86400000);
5182
5239
  },
@@ -5232,10 +5289,10 @@ const WEEKNUM = {
5232
5289
  }
5233
5290
  const y = _date.getFullYear();
5234
5291
  let dayStart = 1;
5235
- let startDayOfFirstWeek = new Date(y, 0, dayStart);
5292
+ let startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5236
5293
  while (startDayOfFirstWeek.getDay() !== startDayOfWeek) {
5237
5294
  dayStart += 1;
5238
- startDayOfFirstWeek = new Date(y, 0, dayStart);
5295
+ startDayOfFirstWeek = new DateTime(y, 0, dayStart);
5239
5296
  }
5240
5297
  const dif = (_date.getTime() - startDayOfFirstWeek.getTime()) / 86400000;
5241
5298
  if (dif < 0) {
@@ -5289,7 +5346,7 @@ const WORKDAY_INTL = {
5289
5346
  timesHoliday.add(holiday.getTime());
5290
5347
  });
5291
5348
  }
5292
- let stepDate = new Date(_startDate.getTime());
5349
+ let stepDate = DateTime.fromTimestamp(_startDate.getTime());
5293
5350
  let timeStepDate = stepDate.getTime();
5294
5351
  const unitDay = Math.sign(_numDays);
5295
5352
  let stepDay = Math.abs(_numDays);
@@ -18650,15 +18707,20 @@ class EvaluationPlugin extends UIPlugin {
18650
18707
  // Getters
18651
18708
  // ---------------------------------------------------------------------------
18652
18709
  evaluateFormula(formulaString, sheetId = this.getters.getActiveSheetId()) {
18653
- let formula = normalize(formulaString);
18654
- const compiledFormula = compile(formula);
18655
- const params = this.getFormulaParameters(() => { });
18656
- const ranges = [];
18657
- for (let xc of formula.dependencies.references) {
18658
- ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
18710
+ try {
18711
+ let formula = normalize(formulaString);
18712
+ const compiledFormula = compile(formula);
18713
+ const params = this.getFormulaParameters(() => { });
18714
+ const ranges = [];
18715
+ for (let xc of formula.dependencies.references) {
18716
+ ranges.push(this.getters.getRangeFromSheetXC(sheetId, xc));
18717
+ }
18718
+ const dependencies = { ...formula.dependencies, references: ranges };
18719
+ return compiledFormula(dependencies, sheetId, ...params);
18720
+ }
18721
+ catch (error) {
18722
+ return "#ERROR";
18659
18723
  }
18660
- const dependencies = { ...formula.dependencies, references: ranges };
18661
- return compiledFormula(dependencies, sheetId, ...params);
18662
18724
  }
18663
18725
  /**
18664
18726
  * Return the value of each cell in the range as they are displayed in the grid.
@@ -19153,25 +19215,26 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
19153
19215
  */
19154
19216
  this.rulePredicate = {
19155
19217
  CellIsRule: (cell, rule) => {
19218
+ var _a, _b, _c, _d, _e, _f;
19156
19219
  if (cell && cell.evaluated.type === CellValueType.error) {
19157
19220
  return false;
19158
19221
  }
19159
19222
  const values = rule.values.map(parsePrimitiveContent);
19160
19223
  switch (rule.operator) {
19161
19224
  case "IsEmpty":
19162
- return !isDefined(cell) || cell.evaluated.value.toString().trim() === "";
19225
+ return !isDefined(cell) || ((_a = cell.evaluated.value) === null || _a === void 0 ? void 0 : _a.toString().trim()) === "";
19163
19226
  case "IsNotEmpty":
19164
- return isDefined(cell) && cell.evaluated.value.toString().trim() !== "";
19227
+ return isDefined(cell) && ((_b = cell.evaluated.value) === null || _b === void 0 ? void 0 : _b.toString().trim()) !== "";
19165
19228
  case "BeginsWith":
19166
19229
  if (!cell && values[0] === "") {
19167
19230
  return false;
19168
19231
  }
19169
- return (isDefined(cell) && (cell === null || cell === void 0 ? void 0 : cell.evaluated.value.toString().startsWith(values[0].toString())));
19232
+ return (isDefined(cell) && ((_c = cell.evaluated.value) === null || _c === void 0 ? void 0 : _c.toString().startsWith(values[0].toString())));
19170
19233
  case "EndsWith":
19171
19234
  if (!cell && values[0] === "") {
19172
19235
  return false;
19173
19236
  }
19174
- return isDefined(cell) && cell.evaluated.value.toString().endsWith(values[0].toString());
19237
+ return isDefined(cell) && ((_d = cell.evaluated.value) === null || _d === void 0 ? void 0 : _d.toString().endsWith(values[0].toString()));
19175
19238
  case "Between":
19176
19239
  return (isDefined(cell) &&
19177
19240
  cell.evaluated.value >= values[0] &&
@@ -19181,11 +19244,11 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
19181
19244
  cell.evaluated.value >= values[0] &&
19182
19245
  cell.evaluated.value <= values[1]);
19183
19246
  case "ContainsText":
19184
- return (isDefined(cell) && cell.evaluated.value.toString().indexOf(values[0].toString()) > -1);
19247
+ return (isDefined(cell) && ((_e = cell.evaluated.value) === null || _e === void 0 ? void 0 : _e.toString().indexOf(values[0].toString())) > -1);
19185
19248
  case "NotContains":
19186
19249
  return (!isDefined(cell) ||
19187
19250
  !cell.evaluated.value ||
19188
- cell.evaluated.value.toString().indexOf(values[0].toString()) == -1);
19251
+ ((_f = cell.evaluated.value) === null || _f === void 0 ? void 0 : _f.toString().indexOf(values[0].toString())) == -1);
19189
19252
  case "GreaterThan":
19190
19253
  return isDefined(cell) && cell.evaluated.value > values[0];
19191
19254
  case "GreaterThanOrEqual":
@@ -19294,39 +19357,34 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
19294
19357
  this.computedIcons[activeSheetId] = {};
19295
19358
  const computedStyle = this.computedStyles[activeSheetId];
19296
19359
  for (let cf of this.getters.getConditionalFormats(activeSheetId)) {
19297
- try {
19298
- switch (cf.rule.type) {
19299
- case "ColorScaleRule":
19300
- for (let range of cf.ranges) {
19301
- this.applyColorScale(range, cf.rule);
19302
- }
19303
- break;
19304
- case "IconSetRule":
19305
- for (let range of cf.ranges) {
19306
- this.applyIcon(range, cf.rule);
19307
- }
19308
- break;
19309
- default:
19310
- for (let ref of cf.ranges) {
19311
- const zone = toZone(ref);
19312
- for (let row = zone.top; row <= zone.bottom; row++) {
19313
- for (let col = zone.left; col <= zone.right; col++) {
19314
- const pr = this.rulePredicate[cf.rule.type];
19315
- let cell = this.getters.getCell(activeSheetId, col, row);
19316
- if (pr && pr(cell, cf.rule)) {
19317
- if (!computedStyle[col])
19318
- computedStyle[col] = [];
19319
- // we must combine all the properties of all the CF rules applied to the given cell
19320
- computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
19321
- }
19360
+ switch (cf.rule.type) {
19361
+ case "ColorScaleRule":
19362
+ for (let range of cf.ranges) {
19363
+ this.applyColorScale(range, cf.rule);
19364
+ }
19365
+ break;
19366
+ case "IconSetRule":
19367
+ for (let range of cf.ranges) {
19368
+ this.applyIcon(range, cf.rule);
19369
+ }
19370
+ break;
19371
+ default:
19372
+ for (let ref of cf.ranges) {
19373
+ const zone = toZone(ref);
19374
+ for (let row = zone.top; row <= zone.bottom; row++) {
19375
+ for (let col = zone.left; col <= zone.right; col++) {
19376
+ const pr = this.rulePredicate[cf.rule.type];
19377
+ let cell = this.getters.getCell(activeSheetId, col, row);
19378
+ if (pr && pr(cell, cf.rule)) {
19379
+ if (!computedStyle[col])
19380
+ computedStyle[col] = [];
19381
+ // we must combine all the properties of all the CF rules applied to the given cell
19382
+ computedStyle[col][row] = Object.assign(((_a = computedStyle[col]) === null || _a === void 0 ? void 0 : _a[row]) || {}, cf.rule.style);
19322
19383
  }
19323
19384
  }
19324
19385
  }
19325
- break;
19326
- }
19327
- }
19328
- catch (_) {
19329
- // we don't care about the errors within the evaluation of a rule
19386
+ }
19387
+ break;
19330
19388
  }
19331
19389
  }
19332
19390
  }
@@ -19345,7 +19403,7 @@ class EvaluationConditionalFormatPlugin extends UIPlugin {
19345
19403
  return this.getters.evaluateFormula(`=PERCENTILE(${range},${Number(threshold.value) / 100})`);
19346
19404
  case "formula":
19347
19405
  const value = threshold.value && this.getters.evaluateFormula(threshold.value);
19348
- return !(value instanceof Promise) ? value : null;
19406
+ return typeof value === "number" ? value : null;
19349
19407
  default:
19350
19408
  return null;
19351
19409
  }
@@ -31405,6 +31463,6 @@ const helpers = {
31405
31463
  export { CommandResult, CorePlugin, DATETIME_FORMAT, DataSource, DispatchResult, Model, Revision, SPREADSHEET_DIMENSIONS, Spreadsheet, UIPlugin, DEBUG as __DEBUG__, __info__, astToFormula, cellTypes, convertAstNodes, coreTypes, functionCache, helpers, invalidateEvaluationCommands, normalize, parse, readonlyAllowedCommands, registries, setTranslationMethod };
31406
31464
 
31407
31465
 
31408
- __info__.version = '15.0.14';
31409
- __info__.date = '2023-11-24T13:06:57.405Z';
31410
- __info__.hash = 'c9a805f';
31466
+ __info__.version = '15.0.16';
31467
+ __info__.date = '2024-01-17T10:23:17.942Z';
31468
+ __info__.hash = '3a9ce19';