@syncfusion/ej2-calculate 35.1.37

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.
Files changed (173) hide show
  1. package/.eslintrc.json +263 -0
  2. package/README.md +132 -0
  3. package/base.d.ts +4 -0
  4. package/base.js +4 -0
  5. package/common.d.ts +4 -0
  6. package/common.js +4 -0
  7. package/dist/ej2-calculate.umd.min.js +11 -0
  8. package/dist/ej2-calculate.umd.min.js.map +1 -0
  9. package/dist/es6/ej2-calculate.es2015.js +24801 -0
  10. package/dist/es6/ej2-calculate.es2015.js.map +1 -0
  11. package/dist/es6/ej2-calculate.es5.js +27229 -0
  12. package/dist/es6/ej2-calculate.es5.js.map +1 -0
  13. package/dist/global/ej2-calculate.min.js +11 -0
  14. package/dist/global/ej2-calculate.min.js.map +1 -0
  15. package/dist/global/index.d.ts +14 -0
  16. package/formulas.d.ts +4 -0
  17. package/formulas.js +4 -0
  18. package/index.d.ts +4 -0
  19. package/index.js +4 -0
  20. package/license +10 -0
  21. package/package.json +30 -0
  22. package/src/base/calculate-model.d.ts +4 -0
  23. package/src/base/calculate-model.js +0 -0
  24. package/src/base/calculate.d.ts +1105 -0
  25. package/src/base/calculate.js +4720 -0
  26. package/src/base/index.d.ts +8 -0
  27. package/src/base/index.js +7 -0
  28. package/src/base/parser.d.ts +208 -0
  29. package/src/base/parser.js +1512 -0
  30. package/src/common/address.d.ts +59 -0
  31. package/src/common/address.js +96 -0
  32. package/src/common/cell-ref.d.ts +32 -0
  33. package/src/common/cell-ref.js +112 -0
  34. package/src/common/common.d.ts +44 -0
  35. package/src/common/common.js +134 -0
  36. package/src/common/enum.d.ts +94 -0
  37. package/src/common/enum.js +97 -0
  38. package/src/common/index.d.ts +9 -0
  39. package/src/common/index.js +8 -0
  40. package/src/common/interface.d.ts +122 -0
  41. package/src/common/interface.js +0 -0
  42. package/src/common/l10n.d.ts +24 -0
  43. package/src/common/l10n.js +54 -0
  44. package/src/common/number-date.d.ts +26 -0
  45. package/src/common/number-date.js +38 -0
  46. package/src/common/sheet-info.d.ts +10 -0
  47. package/src/common/sheet-info.js +17 -0
  48. package/src/common/sort.d.ts +17 -0
  49. package/src/common/sort.js +44 -0
  50. package/src/formulas/array.d.ts +47 -0
  51. package/src/formulas/array.js +718 -0
  52. package/src/formulas/basic.d.ts +47 -0
  53. package/src/formulas/basic.js +181 -0
  54. package/src/formulas/complex-numbers.d.ts +207 -0
  55. package/src/formulas/complex-numbers.js +549 -0
  56. package/src/formulas/database.d.ts +152 -0
  57. package/src/formulas/database.js +579 -0
  58. package/src/formulas/date-time-extra.d.ts +97 -0
  59. package/src/formulas/date-time-extra.js +415 -0
  60. package/src/formulas/date-time-intl.d.ts +57 -0
  61. package/src/formulas/date-time-intl.js +309 -0
  62. package/src/formulas/date-time.d.ts +164 -0
  63. package/src/formulas/date-time.js +1021 -0
  64. package/src/formulas/engineering-base.d.ts +150 -0
  65. package/src/formulas/engineering-base.js +404 -0
  66. package/src/formulas/engineering-bessel.d.ts +65 -0
  67. package/src/formulas/engineering-bessel.js +167 -0
  68. package/src/formulas/engineering-convert.d.ts +35 -0
  69. package/src/formulas/engineering-convert.js +120 -0
  70. package/src/formulas/engineering-misc.d.ts +64 -0
  71. package/src/formulas/engineering-misc.js +168 -0
  72. package/src/formulas/financial-amortization-ecma.d.ts +87 -0
  73. package/src/formulas/financial-amortization-ecma.js +288 -0
  74. package/src/formulas/financial-annuity.d.ts +104 -0
  75. package/src/formulas/financial-annuity.js +419 -0
  76. package/src/formulas/financial-bond-helpers.d.ts +106 -0
  77. package/src/formulas/financial-bond-helpers.js +190 -0
  78. package/src/formulas/financial-cashflow.d.ts +47 -0
  79. package/src/formulas/financial-cashflow.js +203 -0
  80. package/src/formulas/financial-coupons.d.ts +227 -0
  81. package/src/formulas/financial-coupons.js +810 -0
  82. package/src/formulas/financial-depreciation.d.ts +64 -0
  83. package/src/formulas/financial-depreciation.js +247 -0
  84. package/src/formulas/financial-rates.d.ts +54 -0
  85. package/src/formulas/financial-rates.js +140 -0
  86. package/src/formulas/financial-securities.d.ts +126 -0
  87. package/src/formulas/financial-securities.js +488 -0
  88. package/src/formulas/formula-math-helpers.d.ts +212 -0
  89. package/src/formulas/formula-math-helpers.js +599 -0
  90. package/src/formulas/formula-module-base.d.ts +54 -0
  91. package/src/formulas/formula-module-base.js +125 -0
  92. package/src/formulas/formula-owner.d.ts +17 -0
  93. package/src/formulas/formula-owner.js +0 -0
  94. package/src/formulas/index.d.ts +68 -0
  95. package/src/formulas/index.js +67 -0
  96. package/src/formulas/information-advanced.d.ts +44 -0
  97. package/src/formulas/information-advanced.js +157 -0
  98. package/src/formulas/information-ecma.d.ts +33 -0
  99. package/src/formulas/information-ecma.js +88 -0
  100. package/src/formulas/information-extra.d.ts +146 -0
  101. package/src/formulas/information-extra.js +351 -0
  102. package/src/formulas/information.d.ts +34 -0
  103. package/src/formulas/information.js +78 -0
  104. package/src/formulas/logical-extra.d.ts +75 -0
  105. package/src/formulas/logical-extra.js +217 -0
  106. package/src/formulas/logical.d.ts +83 -0
  107. package/src/formulas/logical.js +296 -0
  108. package/src/formulas/lookup-array.d.ts +98 -0
  109. package/src/formulas/lookup-array.js +364 -0
  110. package/src/formulas/lookup-ref-extra.d.ts +64 -0
  111. package/src/formulas/lookup-ref-extra.js +180 -0
  112. package/src/formulas/lookup-ref.d.ts +84 -0
  113. package/src/formulas/lookup-ref.js +263 -0
  114. package/src/formulas/lookup.d.ts +114 -0
  115. package/src/formulas/lookup.js +881 -0
  116. package/src/formulas/math-aggregate.d.ts +74 -0
  117. package/src/formulas/math-aggregate.js +376 -0
  118. package/src/formulas/math-ceiling-ecma.d.ts +42 -0
  119. package/src/formulas/math-ceiling-ecma.js +123 -0
  120. package/src/formulas/math-combinatorics.d.ts +75 -0
  121. package/src/formulas/math-combinatorics.js +290 -0
  122. package/src/formulas/math-misc.d.ts +164 -0
  123. package/src/formulas/math-misc.js +889 -0
  124. package/src/formulas/math-number.d.ts +76 -0
  125. package/src/formulas/math-number.js +261 -0
  126. package/src/formulas/math-rounding.d.ts +115 -0
  127. package/src/formulas/math-rounding.js +728 -0
  128. package/src/formulas/math-trig-hyperbolic.d.ts +55 -0
  129. package/src/formulas/math-trig-hyperbolic.js +113 -0
  130. package/src/formulas/math-trig.d.ts +165 -0
  131. package/src/formulas/math-trig.js +334 -0
  132. package/src/formulas/matrix-base.d.ts +13 -0
  133. package/src/formulas/matrix-base.js +169 -0
  134. package/src/formulas/matrix.d.ts +64 -0
  135. package/src/formulas/matrix.js +161 -0
  136. package/src/formulas/regression-ecma.d.ts +66 -0
  137. package/src/formulas/regression-ecma.js +234 -0
  138. package/src/formulas/statistical-advanced.d.ts +125 -0
  139. package/src/formulas/statistical-advanced.js +756 -0
  140. package/src/formulas/statistical-correlation.d.ts +75 -0
  141. package/src/formulas/statistical-correlation.js +198 -0
  142. package/src/formulas/statistical-dispersion.d.ts +108 -0
  143. package/src/formulas/statistical-dispersion.js +337 -0
  144. package/src/formulas/statistical-distribution-extended.d.ts +176 -0
  145. package/src/formulas/statistical-distribution-extended.js +668 -0
  146. package/src/formulas/statistical-distribution.d.ts +104 -0
  147. package/src/formulas/statistical-distribution.js +368 -0
  148. package/src/formulas/statistical-ecma.d.ts +95 -0
  149. package/src/formulas/statistical-ecma.js +392 -0
  150. package/src/formulas/statistical-extended.d.ts +136 -0
  151. package/src/formulas/statistical-extended.js +340 -0
  152. package/src/formulas/statistical-ifs.d.ts +46 -0
  153. package/src/formulas/statistical-ifs.js +180 -0
  154. package/src/formulas/statistical-moments.d.ts +84 -0
  155. package/src/formulas/statistical-moments.js +269 -0
  156. package/src/formulas/statistical-percentile.d.ts +56 -0
  157. package/src/formulas/statistical-percentile.js +195 -0
  158. package/src/formulas/statistical-sample-base.d.ts +14 -0
  159. package/src/formulas/statistical-sample-base.js +124 -0
  160. package/src/formulas/statistical.d.ts +135 -0
  161. package/src/formulas/statistical.js +542 -0
  162. package/src/formulas/text-advanced.d.ts +64 -0
  163. package/src/formulas/text-advanced.js +222 -0
  164. package/src/formulas/text-ecma.d.ts +54 -0
  165. package/src/formulas/text-ecma.js +106 -0
  166. package/src/formulas/text-extra.d.ts +216 -0
  167. package/src/formulas/text-extra.js +657 -0
  168. package/src/formulas/text.d.ts +125 -0
  169. package/src/formulas/text.js +628 -0
  170. package/src/global.js +1 -0
  171. package/src/index.d.ts +14 -0
  172. package/src/index.js +14 -0
  173. package/tslint.json +111 -0
@@ -0,0 +1,4720 @@
1
+ var __extends = (this && this.__extends) || (function () {
2
+ var extendStatics = function (d, b) {
3
+ extendStatics = Object.setPrototypeOf ||
4
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
5
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
6
+ return extendStatics(d, b);
7
+ };
8
+ return function (d, b) {
9
+ extendStatics(d, b);
10
+ function __() { this.constructor = d; }
11
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
12
+ };
13
+ })();
14
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
15
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
16
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
17
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
18
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
19
+ };
20
+ /* eslint-disable @typescript-eslint/no-explicit-any */
21
+ import { getValue, Event, NotifyPropertyChanges, Base, isNullOrUndefined, isUndefined, L10n } from '@syncfusion/ej2-base';
22
+ import { BasicFormulas } from './../formulas/index';
23
+ import { CommonErrors, FormulasErrorsStrings } from '../common/enum';
24
+ import { getRangeIndexes, getCellIndexes, getCellAddress, getRangeAddress } from '../common/address';
25
+ import { isDateTime } from '../common/number-date';
26
+ import { getSheetIndexByName } from '../common/sheet-info';
27
+ import { createSortComparer } from '../common/sort';
28
+ import { calculateDefaultLocale } from '../common/l10n';
29
+ import { Parser } from './parser';
30
+ var maxRows = 1048576;
31
+ var maxCols = 16384;
32
+ /**
33
+ * Excel-compatible formula calculation engine.
34
+ *
35
+ * Register sheets, named ranges, and cell values, then evaluate formulas with
36
+ * {@link Calculate.computeFormula} or refresh dependent cells after edits.
37
+ *
38
+ * Built-in library functions are registered by {@link BasicFormulas} (math, text,
39
+ * logical, lookup, financial, statistical, engineering, and ECMA-376 extensions).
40
+ *
41
+ * @remarks
42
+ * Integrate with a workbook by passing an {@link ICalculateHost} to the constructor,
43
+ * or use standalone key/value storage via {@link Calculate.setKeyValue}.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * import { Calculate } from '@syncfusion/ej2-calculate';
48
+ *
49
+ * const engine = new Calculate();
50
+ * engine.setKeyValue('A1', '10');
51
+ * engine.setKeyValue('A2', '20');
52
+ * const sum = engine.computeFormula('=SUM(A1:A2)'); // '30'
53
+ * engine.destroy();
54
+ * ```
55
+ */
56
+ var Calculate = /** @class */ (function (_super) {
57
+ __extends(Calculate, _super);
58
+ /**
59
+ * Creates a Calculate engine and registers built-in formulas.
60
+ *
61
+ * @param {Object} parent - Optional host implementing {@link ICalculateHost} (for example a workbook),
62
+ * or omit for a standalone engine that stores values with {@link setKeyValue}.
63
+ */
64
+ function Calculate(parent) {
65
+ var _this = _super.call(this, null, null) || this;
66
+ _this.lFormulas = new Map();
67
+ /** @hidden */
68
+ _this.storedData = new Map();
69
+ _this.keyToRowsMap = new Map();
70
+ _this.rowsToKeyMap = new Map();
71
+ /** @hidden */
72
+ _this.rightBracket = String.fromCharCode(161);
73
+ /** @hidden */
74
+ _this.leftBracket = String.fromCharCode(162);
75
+ /** @hidden */
76
+ _this.sheetToken = '!';
77
+ /**
78
+ * Active cell reference currently being evaluated (may include a sheet token).
79
+ *
80
+ * @hidden
81
+ */
82
+ _this.cell = '';
83
+ _this.cellPrefix = '!0!A';
84
+ _this.treatEmptyStringAsZero = false;
85
+ /** @hidden */
86
+ _this.tic = '"';
87
+ /** @hidden */
88
+ _this.singleTic = '\'';
89
+ /** @hidden */
90
+ _this.trueValue = 'TRUE';
91
+ /** @hidden */
92
+ _this.falseValue = 'FALSE';
93
+ _this.parseDecimalSeparator = '.';
94
+ /** @hidden */
95
+ _this.arithMarker = String.fromCharCode(180);
96
+ /** @hidden */
97
+ _this.arithMarker2 = _this.arithMarker + _this.arithMarker;
98
+ _this.dependentCells = null;
99
+ _this.dependentFormulaCells = null;
100
+ /**
101
+ * Minimum numeric bound used by library formulas that clamp results.
102
+ *
103
+ * @hidden
104
+ */
105
+ _this.minValue = Number.MIN_SAFE_INTEGER;
106
+ /**
107
+ * Maximum numeric bound used by library formulas that clamp results.
108
+ *
109
+ * @hidden
110
+ */
111
+ _this.maxValue = Number.MAX_SAFE_INTEGER;
112
+ /**
113
+ * Formula category labels used by Insert Function UI integrations.
114
+ * The `'All'` entry is localized via Syncfusion {@link L10n} (key `CategoryAll`).
115
+ *
116
+ * @hidden
117
+ */
118
+ _this.categoryCollection = ['All'];
119
+ /**
120
+ * Nesting depth counter used while walking formula dependencies.
121
+ *
122
+ * @hidden
123
+ */
124
+ _this.dependencyLevel = 0;
125
+ /** @hidden */
126
+ _this.randomValues = new Map();
127
+ /** @hidden */
128
+ _this.isRandomVal = false;
129
+ /** @hidden */
130
+ _this.randCollection = [];
131
+ /** @hidden */
132
+ _this.dependencyCollection = [];
133
+ /** @hidden */
134
+ _this.uniqueRange = [];
135
+ /** @hidden */
136
+ _this.sortRange = [];
137
+ /**
138
+ * Parser and engine failure messages indexed by {@link FormulasErrorsStrings}.
139
+ *
140
+ * Prose entries are localized via {@link L10n} / {@link setLocale}. Excel error
141
+ * tokens in this array (`#NAME?`, `#CIRCULARREF!`, `#SPILL!`, `#DIV/0!`) stay
142
+ * English for workbook compatibility.
143
+ *
144
+ * @hidden
145
+ */
146
+ _this.formulaErrorStrings = [];
147
+ _this.errorStrings = null;
148
+ _this.parseArgumentSeparator = ',';
149
+ _this.dateTime1900 = new Date(1900, 0, 1, 0, 0, 0);
150
+ _this.isParseDecimalSeparatorChanged = false;
151
+ _this.isArgumentSeparatorChanged = false;
152
+ _this.sheetFamilyID = 0;
153
+ _this.defaultFamilyItem = null;
154
+ _this.sheetFamiliesList = null;
155
+ _this.modelToSheetID = null;
156
+ /** @hidden */
157
+ _this.tokenCount = 0;
158
+ _this.sortedSheetNames = null;
159
+ _this.tempSheetPlaceHolder = String.fromCharCode(133);
160
+ /** @hidden */
161
+ _this.namedRanges = new Map();
162
+ _this.formulaInfoTable = null;
163
+ _this.millisecondsOfaDay = 24 * 60 * 60 * 1000;
164
+ _this.parseDateTimeSeparator = '/';
165
+ /** Keys currently being evaluated via {@link getKeyValue} (guards row-map recursion). */
166
+ _this.evaluatingKeys = new Set();
167
+ var host = parent;
168
+ var locale = (host && host.locale) ? host.locale : 'en-US';
169
+ _this.l10n = new L10n('calculate', calculateDefaultLocale, locale);
170
+ _this.refreshLocalizedStrings();
171
+ new BasicFormulas(_this);
172
+ _this.parentObject = isNullOrUndefined(parent) ? _this : parent;
173
+ _this.grid = _this.parentObject;
174
+ _this.parser = new Parser(_this);
175
+ return _this;
176
+ }
177
+ Object.defineProperty(Calculate.prototype, "libraryFormulas", {
178
+ /**
179
+ * Registered library formula collection (name → handler metadata).
180
+ *
181
+ * Prefer {@link getLibraryFormulas} for read access. The setter accepts a single
182
+ * formula registration payload used during built-in and custom registration.
183
+ *
184
+ * @hidden
185
+ * @returns {any} - Registered library formula collection.
186
+ */
187
+ get: function () {
188
+ return this.lFormulas;
189
+ },
190
+ set: function (formulaColl) {
191
+ this.lFormulas.set(formulaColl.fName, { handler: formulaColl.handler, category: formulaColl.category, description: formulaColl.description });
192
+ },
193
+ enumerable: true,
194
+ configurable: true
195
+ });
196
+ /**
197
+ * Applies culture-specific prose for parser/engine messages and category labels.
198
+ *
199
+ * Excel error tokens (`#VALUE!`, …), `TRUE`/`FALSE`, and English function names
200
+ * are not localized.
201
+ *
202
+ * @hidden
203
+ * @param {string} locale - Culture id (for example `"fr-FR"`). Defaults to host `locale` or `"en-US"`.
204
+ * @returns {void}
205
+ */
206
+ Calculate.prototype.setLocale = function (locale) {
207
+ var host = this.parentObject;
208
+ var next = locale || (host && host.locale) || 'en-US';
209
+ this.l10n.setLocale(next);
210
+ this.refreshLocalizedStrings();
211
+ };
212
+ /**
213
+ * Rebuilds {@link formulaErrorStrings} and {@link categoryCollection} from L10n.
214
+ *
215
+ * @hidden
216
+ * @returns {void}
217
+ */
218
+ Calculate.prototype.refreshLocalizedStrings = function () {
219
+ var _this = this;
220
+ var t = function (key) { return _this.l10n.getConstant(key); };
221
+ this.formulaErrorStrings = [
222
+ t('OperatorsCannotStartWithExpression'),
223
+ t('CannotParse'),
224
+ t('BadLibrary'),
225
+ t('InvalidCharInFrontOf'),
226
+ t('NumberContains2DecimalPoints'),
227
+ t('ExpressionCannotEndWithAnOperator'),
228
+ t('InvalidCharactersFollowingWithOperator'),
229
+ t('InvalidCharInNumber'),
230
+ t('MismatchedParentheses'),
231
+ t('UnknownFormulaName'),
232
+ t('RequiresASingleArgument'),
233
+ t('Requires3Args'),
234
+ t('InvalidMathArgument'),
235
+ t('Requires2Args'),
236
+ '#NAME?',
237
+ t('TooComplex'),
238
+ '#CIRCULARREF!',
239
+ t('MissingFormula'),
240
+ t('ImproperFormula'),
241
+ t('InvalidExpression'),
242
+ t('CellEmpty'),
243
+ t('BadFormula'),
244
+ t('EmptyExpression'),
245
+ '',
246
+ t('MismatchedTics'),
247
+ t('WrongNumberArguments'),
248
+ t('InvalidArguments'),
249
+ t('IterationsDoNotConverge'),
250
+ t('AlreadyRegistered'),
251
+ t('CalculationOverflow'),
252
+ t('MissingSheet'),
253
+ t('CannotParseUnderscore'),
254
+ t('ExpressionCannotEndWithAnOperatorUnderscore'),
255
+ '#SPILL!',
256
+ '#DIV/0!'
257
+ ];
258
+ this.categoryCollection = [t('CategoryAll')];
259
+ };
260
+ /**
261
+ * Returns sheet metadata from the calculate host when available.
262
+ *
263
+ * @returns {Object} - Sheet info entries from {@link ICalculateHost.getSheetInfo}, or an empty array.
264
+ * @hidden
265
+ */
266
+ Calculate.prototype.getHostSheetInfo = function () {
267
+ var host = this.parentObject;
268
+ if (host && typeof host.getSheetInfo === 'function') {
269
+ return host.getSheetInfo() || [];
270
+ }
271
+ return [];
272
+ };
273
+ /**
274
+ * Parses a date/time string via the host when {@link ICalculateHost.parseDate} is implemented.
275
+ *
276
+ * @param {string | number | boolean | Object} value - Date or time text to parse.
277
+ * @returns {Object} - Host parse result, or an empty object when no host parser is available.
278
+ * @hidden
279
+ */
280
+ Calculate.prototype.hostParseDate = function (value) {
281
+ var host = this.parentObject;
282
+ if (host && typeof host.parseDate === 'function') {
283
+ return host.parseDate(value) || {};
284
+ }
285
+ return {};
286
+ };
287
+ /**
288
+ * Gets the culture-aware separator used to split formula arguments (typically `,` or `;`).
289
+ *
290
+ * @hidden
291
+ * @returns {string} - Argument separator string.
292
+ */
293
+ Calculate.prototype.getParseArgumentSeparator = function () {
294
+ var seperator = ',';
295
+ if (!this.isArgumentSeparatorChanged && seperator !== this.parseArgumentSeparator) {
296
+ this.parseArgumentSeparator = seperator;
297
+ }
298
+ return this.parseArgumentSeparator;
299
+ };
300
+ /**
301
+ * Sets the separator used to split formula arguments.
302
+ *
303
+ * @param {string | number | boolean | Object} value - Argument separator for the current culture (for example `,` or `;`).
304
+ * @returns {void}
305
+ */
306
+ Calculate.prototype.setParseArgumentSeparator = function (value) {
307
+ this.parseArgumentSeparator = value;
308
+ this.isArgumentSeparatorChanged = true;
309
+ };
310
+ /**
311
+ * Gets the date/time component separator used when parsing date literals.
312
+ *
313
+ * @hidden
314
+ * @returns {Date | Object} - Date/time separator string (default `/`).
315
+ */
316
+ Calculate.prototype.getParseDateTimeSeparator = function () {
317
+ return this.parseDateTimeSeparator;
318
+ };
319
+ /**
320
+ * Controls whether empty string cell values are treated as numeric zero in calculations.
321
+ *
322
+ * @param {string | number | boolean | Object} value - When `true`, empty strings coerce to `0`.
323
+ * @returns {void}
324
+ */
325
+ Calculate.prototype.setTreatEmptyStringAsZero = function (value) {
326
+ this.treatEmptyStringAsZero = value;
327
+ };
328
+ /**
329
+ * Returns whether empty string values are treated as numeric zero.
330
+ *
331
+ * @hidden
332
+ * @returns {string | number} - `true` when empty strings coerce to `0`.
333
+ */
334
+ Calculate.prototype.getTreatEmptyStringAsZero = function () {
335
+ return this.treatEmptyStringAsZero;
336
+ };
337
+ /**
338
+ * Sets the date/time component separator used when parsing date literals.
339
+ *
340
+ * @hidden
341
+ * @param {string | number | boolean | Object} value - Separator character or string (for example `/` or `-`).
342
+ * @returns {void}
343
+ */
344
+ Calculate.prototype.setParseDateTimeSeparator = function (value) {
345
+ this.parseDateTimeSeparator = value;
346
+ };
347
+ /**
348
+ * Syncfusion property-change hook (no-op for Calculate; required by {@link INotifyPropertyChanged}).
349
+ *
350
+ * @param {Object} newProp - Updated model properties.
351
+ * @param {Object} oldProp - Previous model properties.
352
+ * @returns {void}
353
+ */
354
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
355
+ Calculate.prototype.onPropertyChanged = function (newProp, oldProp) {
356
+ /** code snippets */
357
+ };
358
+ /**
359
+ * Gets the module name of the Calculate engine.
360
+ *
361
+ * @returns {string} - Returns "calculate" as the component module name.
362
+ */
363
+ Calculate.prototype.getModuleName = function () {
364
+ return 'calculate';
365
+ };
366
+ /**
367
+ * Returns the leading character that marks a formula expression (always `=`).
368
+ *
369
+ * @returns {string} - Formula prefix character.
370
+ * @hidden
371
+ */
372
+ Calculate.prototype.getFormulaCharacter = function () {
373
+ return '=';
374
+ };
375
+ /**
376
+ * Returns whether the first character of `text` is an uppercase A–Z letter.
377
+ *
378
+ * @param {string} text - Text to inspect.
379
+ * @returns {string} - `true` when the first character is uppercase ASCII A-Z.
380
+ * @hidden
381
+ */
382
+ Calculate.prototype.isUpperChar = function (text) {
383
+ var charCode = text.charCodeAt(0);
384
+ return charCode > 64 && charCode < 91;
385
+ };
386
+ Calculate.prototype.resetKeys = function () {
387
+ this.storedData.clear();
388
+ this.keyToRowsMap.clear();
389
+ this.rowsToKeyMap.clear();
390
+ };
391
+ /**
392
+ * Records a dependency from the active formula cell to `cellRef` and detects circular references.
393
+ *
394
+ * @param {string} cellRef - Dependent cell reference (may include a sheet token).
395
+ * @throws When a circular reference is detected.
396
+ * @hidden
397
+ * @returns {void}
398
+ */
399
+ Calculate.prototype.updateDependentCell = function (cellRef) {
400
+ var _this = this;
401
+ var formulaCell = this.cell;
402
+ if (formulaCell !== '') {
403
+ var family = this.getSheetFamilyItem(this.grid);
404
+ if (family.sheetNameToParentObject) {
405
+ if (!formulaCell.includes(this.sheetToken)) {
406
+ formulaCell = family.parentObjectToToken.get(this.grid) + formulaCell;
407
+ }
408
+ if (!cellRef.includes(this.sheetToken)) {
409
+ cellRef = family.parentObjectToToken.get(this.grid) + cellRef;
410
+ }
411
+ }
412
+ if (formulaCell !== cellRef) {
413
+ var dependentCellMap = this.getDependentCells();
414
+ if (!dependentCellMap.has(cellRef)) {
415
+ dependentCellMap.set(cellRef, []);
416
+ }
417
+ var dependentCells = dependentCellMap.get(cellRef);
418
+ if (dependentCells.indexOf(formulaCell) === -1) {
419
+ var formulaDependentCellMap_1 = this.getDependentFormulaCells();
420
+ var cellRefObj_1 = {};
421
+ var checkCircularReference_1 = function (refCell) {
422
+ if (formulaDependentCellMap_1.has(refCell)) {
423
+ var formalaRefCells = formulaDependentCellMap_1.get(refCell);
424
+ if (formalaRefCells.has(formulaCell)) {
425
+ throw _this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
426
+ }
427
+ else if (!cellRefObj_1[refCell]) {
428
+ cellRefObj_1[refCell] = true;
429
+ formalaRefCells.forEach(function (refCell) {
430
+ checkCircularReference_1(refCell);
431
+ });
432
+ }
433
+ }
434
+ };
435
+ checkCircularReference_1(cellRef);
436
+ dependentCells.push(formulaCell);
437
+ if (!formulaDependentCellMap_1.has(formulaCell)) {
438
+ formulaDependentCellMap_1.set(formulaCell, new Map());
439
+ formulaDependentCellMap_1.get(formulaCell).set(cellRef, cellRef);
440
+ }
441
+ else if (!formulaDependentCellMap_1.get(formulaCell).has(cellRef)) {
442
+ formulaDependentCellMap_1.get(formulaCell).set(cellRef, cellRef);
443
+ }
444
+ }
445
+ }
446
+ }
447
+ };
448
+ /**
449
+ * Returns the map of cell references to cells that depend on them.
450
+ *
451
+ * @returns {Object} - Dependency map keyed by referenced cell.
452
+ * @hidden
453
+ */
454
+ Calculate.prototype.getDependentCells = function () {
455
+ if (this.dependentCells == null) {
456
+ this.dependentCells = new Map();
457
+ }
458
+ return this.dependentCells;
459
+ };
460
+ /**
461
+ * Returns the map of formula cells to the references they depend on.
462
+ *
463
+ * @returns {Object} - Nested map of formula cell → referenced cells.
464
+ * @hidden
465
+ */
466
+ Calculate.prototype.getDependentFormulaCells = function () {
467
+ if (this.isSheetMember()) {
468
+ var family = this.getSheetFamilyItem(this.grid);
469
+ if (family.sheetDependentFormulaCells == null) {
470
+ family.sheetDependentFormulaCells = new Map();
471
+ }
472
+ return family.sheetDependentFormulaCells;
473
+ }
474
+ else {
475
+ if (this.dependentFormulaCells == null) {
476
+ this.dependentFormulaCells = new Map();
477
+ }
478
+ return this.dependentFormulaCells;
479
+ }
480
+ };
481
+ /**
482
+ * Returns the map of registered library formula names to their handlers and metadata.
483
+ *
484
+ * @hidden
485
+ * @returns {Object} - Map keyed by uppercase Excel function name (for example `"SUM"`, `"XLOOKUP"`).
486
+ */
487
+ Calculate.prototype.getLibraryFormulas = function () {
488
+ return this.lFormulas;
489
+ };
490
+ /**
491
+ * Returns the handler function for a registered library formula.
492
+ *
493
+ * @hidden
494
+ * @param {string} libFormula - Excel function name (case-insensitive), for example `"SUM"`.
495
+ * @returns {Function | null} - Bound `Compute*` handler, or `null` when the name is not registered.
496
+ *
497
+ * @example
498
+ * ```ts
499
+ * const sum = engine.getFunction('SUM');
500
+ * ```
501
+ */
502
+ Calculate.prototype.getFunction = function (libFormula) {
503
+ if (this.getLibraryFormulas().has(libFormula.toUpperCase())) {
504
+ return this.getLibraryFormulas().get(libFormula.toUpperCase()).handler;
505
+ }
506
+ else {
507
+ return null;
508
+ }
509
+ };
510
+ /**
511
+ * Converts an Excel serial date value to a JavaScript `Date`.
512
+ *
513
+ * @param {string | number} val - Excel serial number as a string.
514
+ * @returns {Date | Object} - Corresponding `Date` (accounts for the Excel 1900 leap-year quirk).
515
+ * @hidden
516
+ */
517
+ Calculate.prototype.intToDate = function (val) {
518
+ var dateVal = Number(val);
519
+ dateVal = (dateVal > 0 && dateVal < 1) ? (1 + dateVal) : (dateVal === 0) ? 1 : dateVal;
520
+ if (dateVal > 60) {
521
+ dateVal -= 1; // Due to leap year issue of 1900 in MSExcel.
522
+ }
523
+ var startDate = new Date('01/01/1900');
524
+ var startDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), startDate.getHours(), startDate.getMinutes(), startDate.getSeconds(), startDate.getMilliseconds());
525
+ return new Date(new Date(((dateVal - 1) * (1000 * 3600 * 24)) + startDateUTC).toUTCString().replace(' GMT', ''));
526
+ };
527
+ /**
528
+ * Returns the formula info table for the active sheet family (or the standalone engine table).
529
+ *
530
+ * @hidden
531
+ * @returns {Object} - Map of cell token → {@link FormulaInfo}.
532
+ */
533
+ Calculate.prototype.getFormulaInfoTable = function () {
534
+ if (this.isSheetMember()) {
535
+ var family = this.getSheetFamilyItem(this.grid);
536
+ if (family.sheetFormulaInfotable === null) {
537
+ family.sheetFormulaInfotable = new Map();
538
+ }
539
+ return family.sheetFormulaInfotable;
540
+ }
541
+ else {
542
+ if (this.formulaInfoTable === null) {
543
+ this.formulaInfoTable = new Map();
544
+ }
545
+ return this.formulaInfoTable;
546
+ }
547
+ };
548
+ /**
549
+ * Gets the decimal separator used when parsing numeric literals.
550
+ *
551
+ * @hidden
552
+ * @returns {string} - Decimal separator string (default `.`).
553
+ */
554
+ Calculate.prototype.getParseDecimalSeparator = function () {
555
+ var seperator = '.';
556
+ if (!this.isParseDecimalSeparatorChanged && seperator !== this.parseDecimalSeparator) {
557
+ this.parseDecimalSeparator = seperator;
558
+ }
559
+ return this.parseDecimalSeparator;
560
+ };
561
+ /**
562
+ * Sets the decimal separator used when parsing numeric literals.
563
+ *
564
+ * @param {string | number | boolean | Object} value - Decimal separator for the current culture (for example `.` or `,`).
565
+ * @returns {void}
566
+ */
567
+ Calculate.prototype.setParseDecimalSeparator = function (value) {
568
+ this.parseDecimalSeparator = value;
569
+ this.isParseDecimalSeparatorChanged = true;
570
+ };
571
+ /**
572
+ * Extracts the sheet token prefix from a cell reference when present.
573
+ *
574
+ * @param {string} cellRef - Cell or range reference that may begin with a sheet token.
575
+ * @returns {string} - Sheet token substring including delimiters, or an empty string.
576
+ * @hidden
577
+ */
578
+ Calculate.prototype.getSheetToken = function (cellRef) {
579
+ var i = 0;
580
+ var temp = '';
581
+ if (i < cellRef.length && cellRef[i] === this.sheetToken) {
582
+ i++;
583
+ while (i < cellRef.length && cellRef[i] !== this.sheetToken) {
584
+ i++;
585
+ }
586
+ temp = cellRef.substring(0, i + 1);
587
+ }
588
+ if (i < cellRef.length) {
589
+ return temp;
590
+ }
591
+ throw this.formulaErrorStrings[FormulasErrorsStrings.BadIndex];
592
+ };
593
+ /**
594
+ * Resolves the sheet family id for a grid/parent object.
595
+ *
596
+ * @param {Object} grd - Grid or parent object registered with the engine.
597
+ * @returns {string | number} - Sheet id, or `-1` when not registered.
598
+ * @hidden
599
+ */
600
+ Calculate.prototype.getSheetID = function (grd) {
601
+ var family = this.getSheetFamilyItem(grd);
602
+ if (family.sheetNameToParentObject != null && family.sheetNameToParentObject.size > 0) {
603
+ var token = family.parentObjectToToken.get(grd);
604
+ if (token) {
605
+ token = token.split(this.sheetToken).join('');
606
+ var id = this.parseFloat(token);
607
+ if (!this.isNaN(id)) {
608
+ return id;
609
+ }
610
+ }
611
+ }
612
+ return -1;
613
+ };
614
+ /**
615
+ * Parses a numeric string using the configured decimal separator.
616
+ *
617
+ * @hidden
618
+ * @param {string | number | boolean | Object} value - Numeric text or number.
619
+ * @returns {number} - Parsed number, or `NaN` when parsing fails.
620
+ */
621
+ Calculate.prototype.parseFloat = function (value) {
622
+ var convertedNum = Number(value);
623
+ if (isNaN(convertedNum) && typeof value === 'string' && value.includes(',')) {
624
+ convertedNum = Number(value.split(',').join(''));
625
+ }
626
+ return convertedNum;
627
+ };
628
+ /**
629
+ * Returns the 1-based row index from a cell reference string.
630
+ *
631
+ * @hidden
632
+ * @param {string} cell - Cell reference (optional sheet token allowed).
633
+ * @returns {number} - Row number, or `-1` when invalid.
634
+ */
635
+ Calculate.prototype.rowIndex = function (cell) {
636
+ var i = 0;
637
+ var isLetter = false;
638
+ if (i < cell.length && cell[i] === this.sheetToken) {
639
+ i++;
640
+ while (i < cell.length && cell[i] !== this.sheetToken) {
641
+ i++;
642
+ }
643
+ i++;
644
+ }
645
+ while (i < cell.length && this.isChar(cell[i])) {
646
+ isLetter = true;
647
+ i++;
648
+ }
649
+ var result = parseInt(cell.substring(i), 10);
650
+ if (i < cell.length && !this.isNaN(result)) {
651
+ return result;
652
+ }
653
+ if (isLetter) {
654
+ return -1;
655
+ }
656
+ throw this.formulaErrorStrings[FormulasErrorsStrings.BadIndex];
657
+ };
658
+ /**
659
+ * Returns the 1-based column index from a cell reference string.
660
+ *
661
+ * @param {string} cell - Cell reference (optional sheet token allowed).
662
+ * @returns {number} - Column number, or `-1` when invalid.
663
+ * @hidden
664
+ */
665
+ Calculate.prototype.colIndex = function (cell) {
666
+ var j = 0;
667
+ var k = 0;
668
+ cell = cell.toUpperCase();
669
+ if (j < cell.length && cell[j] === this.sheetToken) {
670
+ j++;
671
+ while (j < cell.length && cell[j] !== this.sheetToken) {
672
+ j++;
673
+ }
674
+ j++;
675
+ }
676
+ while (j < cell.length && this.isChar(cell[j])) {
677
+ var charCode = cell[j].charCodeAt(0);
678
+ k = k * 26 + charCode - 64;
679
+ j++;
680
+ }
681
+ if (k === 0) {
682
+ return -1;
683
+ }
684
+ return k;
685
+ };
686
+ /**
687
+ * Returns the Excel-compatible error tokens used by the engine (`#N/A`, `#VALUE!`, …).
688
+ *
689
+ * @returns {string[]} - Error string list indexed by {@link CommonErrors}.
690
+ * @hidden
691
+ */
692
+ Calculate.prototype.getErrorStrings = function () {
693
+ if (this.errorStrings === null) {
694
+ this.errorStrings = ['#N/A', '#VALUE!', '#REF!', '#DIV/0!', '#NUM!', '#NAME?', '#NULL!', '#CALC!'];
695
+ }
696
+ return this.errorStrings;
697
+ };
698
+ /**
699
+ * Returns a substring with Excel-style optional length (defaults to remainder of `text`).
700
+ *
701
+ * @param {string} text - Source string.
702
+ * @param {number} startIndex - Zero-based start index.
703
+ * @param {number} length - Optional length; when omitted, returns through the end of `text`.
704
+ * @returns {string} - Substring.
705
+ * @hidden
706
+ */
707
+ Calculate.prototype.substring = function (text, startIndex, length) {
708
+ return text.substring(startIndex, length + startIndex);
709
+ };
710
+ /**
711
+ * Returns whether `c` is an alphabetic character (A–Z or a–z).
712
+ *
713
+ * @param {number} c - Single character or string whose first character is tested.
714
+ * @returns {string | number} - `true` when alphabetic.
715
+ * @hidden
716
+ */
717
+ Calculate.prototype.isChar = function (c) {
718
+ if ((c.charCodeAt(0) >= 65 && c.charCodeAt(0) <= 90) || (c.charCodeAt(0) >= 97 && c.charCodeAt(0) <= 122)) {
719
+ return true;
720
+ }
721
+ return false;
722
+ };
723
+ /**
724
+ * Returns the {@link CalcSheetFamilyItem} for a model/grid, creating family storage as needed.
725
+ *
726
+ * @param {Object} model - Parent grid or sheet model.
727
+ * @param {string | number | Object} calcId - Optional explicit family id.
728
+ * @returns {string | number} - Sheet family item for the model.
729
+ * @hidden
730
+ */
731
+ Calculate.prototype.getSheetFamilyItem = function (model, calcId) {
732
+ if (this.sheetFamilyID === 0) {
733
+ if (this.defaultFamilyItem == null) {
734
+ this.defaultFamilyItem = new CalcSheetFamilyItem();
735
+ }
736
+ return this.defaultFamilyItem;
737
+ }
738
+ if (this.sheetFamiliesList == null) {
739
+ this.sheetFamiliesList = new Map();
740
+ }
741
+ if (calcId === undefined) {
742
+ calcId = this.modelToSheetID.get(model);
743
+ }
744
+ if (!this.sheetFamiliesList.has(calcId)) {
745
+ this.sheetFamiliesList.set(calcId, new CalcSheetFamilyItem());
746
+ }
747
+ return this.sheetFamiliesList.get(calcId);
748
+ };
749
+ /**
750
+ * Stores a standalone key/value (or formula) for evaluation without a workbook host.
751
+ *
752
+ * When `value` starts with `=`, it is treated as a formula and evaluated by {@link getKeyValue}.
753
+ *
754
+ * @param {string} key - Cell-like key (for example `"A1"`).
755
+ * @param {string | number | boolean | Object} value - Literal value or formula text.
756
+ *
757
+ * @example
758
+ * ```ts
759
+ * engine.setKeyValue('A1', '10');
760
+ * engine.setKeyValue('B1', '=A1*2');
761
+ * ```
762
+ * @returns {void}
763
+ */
764
+ Calculate.prototype.setKeyValue = function (key, value) {
765
+ key = key.toUpperCase();
766
+ var str = value.toString().trim();
767
+ if (!this.storedData.get(key) || str.indexOf('{') === 0) {
768
+ this.storedData.set(key, new FormulaInfo());
769
+ this.keyToRowsMap.set(key, this.keyToRowsMap.size + 1);
770
+ this.rowsToKeyMap.set(this.rowsToKeyMap.size + 1, key);
771
+ }
772
+ var fInfo = this.storedData.get(key);
773
+ if (fInfo.getFormulaText() != null && fInfo.getFormulaText().length > 0 && fInfo.getFormulaText() !== str) {
774
+ var s1 = this.cellPrefix + this.keyToRowsMap.get(key).toString();
775
+ var formulaDependent = this.getDependentFormulaCells().get(s1);
776
+ if (formulaDependent != null) {
777
+ this.clearFormulaDependentCells(s1);
778
+ }
779
+ }
780
+ if (str.length > 0 && str[0] === this.getFormulaCharacter()) {
781
+ fInfo.setFormulaText(str);
782
+ }
783
+ else if (fInfo.getFormulaValue() !== str) {
784
+ fInfo.setFormulaText('');
785
+ fInfo.setParsedFormula('');
786
+ fInfo.setFormulaValue(str);
787
+ }
788
+ };
789
+ /**
790
+ * Clears dependency graph entries for a formula cell.
791
+ *
792
+ * @param {string} cell - Formula cell token whose dependencies should be removed.
793
+ * @hidden
794
+ * @returns {void}
795
+ */
796
+ Calculate.prototype.clearFormulaDependentCells = function (cell) {
797
+ var _this = this;
798
+ var dependentFormula = this.getDependentFormulaCells().get(cell);
799
+ if (dependentFormula) {
800
+ dependentFormula.forEach(function (value, key) {
801
+ var s = key;
802
+ var dependent = _this.getDependentCells().get(s);
803
+ _this.arrayRemove(dependent, cell);
804
+ if (dependent.length === 0) {
805
+ _this.getDependentCells().delete(s);
806
+ }
807
+ });
808
+ this.getDependentFormulaCells().delete(cell);
809
+ }
810
+ };
811
+ /**
812
+ * Clears all stored key-value pairs from memory in standalone mode.
813
+ *
814
+ * @returns {void}
815
+ */
816
+ Calculate.prototype.clearKeys = function () {
817
+ this.resetKeys();
818
+ };
819
+ Calculate.prototype.arrayRemove = function (array, value) {
820
+ var index = array.indexOf(value);
821
+ if (index !== -1) {
822
+ array.splice(index, 1);
823
+ }
824
+ return array;
825
+ };
826
+ /**
827
+ * Returns the stored or computed value for a standalone key registered with {@link setKeyValue}.
828
+ *
829
+ * @param {string} key - Cell-like key (case-insensitive).
830
+ * @returns {string} - Computed formula result or stored literal; empty string when missing.
831
+ *
832
+ * @example
833
+ * ```ts
834
+ * engine.setKeyValue('A1', '=1+2');
835
+ * engine.getKeyValue('A1'); // '3'
836
+ * ```
837
+ */
838
+ Calculate.prototype.getKeyValue = function (key) {
839
+ key = key.toUpperCase();
840
+ if (!this.storedData.has(key)) {
841
+ return '';
842
+ }
843
+ var fInfo = this.storedData.get(key);
844
+ var fText = fInfo.getFormulaText();
845
+ if (fText.length > 0 && fText[0] === this.getFormulaCharacter()) {
846
+ if (this.evaluatingKeys.has(key)) {
847
+ return this.getErrorStrings()[CommonErrors.Ref];
848
+ }
849
+ this.evaluatingKeys.add(key);
850
+ this.cell = this.cellPrefix + this.keyToRowsMap.get(key).toString();
851
+ fText = fText.substring(1);
852
+ try {
853
+ try {
854
+ fInfo.setParsedFormula(this.parser.parseFormula(fText, key));
855
+ }
856
+ catch (ex) {
857
+ var args = {
858
+ message: ex.message, exception: ex, isForceCalculable: false,
859
+ computeForceCalculate: false
860
+ };
861
+ this.trigger('onFailure', args);
862
+ fInfo.setFormulaValue(args.message);
863
+ return this.storedData.get(key).getFormulaValue();
864
+ }
865
+ try {
866
+ fInfo.setFormulaValue(this.computeFormula(fInfo.getParsedFormula()));
867
+ }
868
+ catch (ex) {
869
+ var args = {
870
+ message: ex.message, exception: ex, isForceCalculable: false,
871
+ computeForceCalculate: false
872
+ };
873
+ this.trigger('onFailure', args);
874
+ var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message;
875
+ return (isNullOrUndefined(this.getErrorLine(ex)) ? '' : '#' + this.getErrorLine(ex) + ': ') + errorMessage;
876
+ }
877
+ }
878
+ finally {
879
+ this.evaluatingKeys.delete(key);
880
+ }
881
+ }
882
+ return this.storedData.get(key).getFormulaValue();
883
+ };
884
+ /**
885
+ * Returns the named range map (name → range address).
886
+ *
887
+ * @hidden
888
+ * @returns {Object} - Mutable map of named ranges.
889
+ */
890
+ Calculate.prototype.getNamedRanges = function () {
891
+ return this.namedRanges;
892
+ };
893
+ /**
894
+ * Adds or replaces a named range.
895
+ *
896
+ * @param {string} name - Range name (optionally `Sheet!Name` scoped).
897
+ * @param {string} range - Address or formula text associated with the name.
898
+ * @returns {string} - `true` when the name was registered; `false` when sheet scope could not be resolved.
899
+ */
900
+ Calculate.prototype.addNamedRange = function (name, range) {
901
+ var sheetScopeName = name.split(this.sheetToken);
902
+ if (sheetScopeName.length > 1) {
903
+ var sheetId = (this.getSheetId(this.grid)).toString();
904
+ var family = this.getSheetFamilyItem(sheetId);
905
+ if (!family.parentObjectToToken.get(sheetId)) {
906
+ return false;
907
+ }
908
+ name = sheetScopeName[0] + this.sheetToken + sheetScopeName[1].toUpperCase();
909
+ }
910
+ else {
911
+ name = name.toUpperCase();
912
+ }
913
+ this.namedRanges.set(name, range);
914
+ return true;
915
+ };
916
+ /**
917
+ * Rewrites named-range keys after a sheet rename.
918
+ *
919
+ * @param {string} pName - Previous sheet name segment.
920
+ * @param {string} name - New sheet name segment.
921
+ * @hidden
922
+ * @returns {void}
923
+ */
924
+ Calculate.prototype.updateNamedRange = function (pName, name) {
925
+ var updatedRange = new Map();
926
+ this.namedRanges.forEach(function (value, key) {
927
+ var updatedKey = key;
928
+ if (key.includes(pName)) {
929
+ var range = key.split('!');
930
+ range[0] = name;
931
+ updatedKey = range.join('!');
932
+ }
933
+ updatedRange.set(updatedKey, value);
934
+ });
935
+ this.namedRanges = updatedRange;
936
+ };
937
+ /**
938
+ * Removes a named range by name.
939
+ *
940
+ * @param {string} name - Named range to remove (case-insensitive).
941
+ * @returns {string} - `true` when the name existed and was removed.
942
+ */
943
+ Calculate.prototype.removeNamedRange = function (name) {
944
+ name = name.toUpperCase();
945
+ if (this.namedRanges.get(name) != null) {
946
+ this.namedRanges.delete(name);
947
+ return true;
948
+ }
949
+ return false;
950
+ };
951
+ /**
952
+ * Converts a 1-based column number to Excel column letters (`1` → `"A"`, `27` → `"AA"`).
953
+ *
954
+ * @param {number} col - 1-based column index.
955
+ * @returns {string | number} - Column letters.
956
+ * @hidden
957
+ */
958
+ Calculate.prototype.convertAlpha = function (col) {
959
+ var arrCol = [];
960
+ var n = 0;
961
+ var charText = 'A';
962
+ while (col > 0) {
963
+ col--;
964
+ var aCharValue = charText.charCodeAt(0);
965
+ arrCol[n] = String.fromCharCode(col % 26 + aCharValue);
966
+ col = parseInt((col / 26).toString(), 10);
967
+ n++;
968
+ }
969
+ var arr = [];
970
+ for (var i = 0; i < n; i++) {
971
+ arr[n - i - 1] = arrCol[i];
972
+ }
973
+ return arr.join('');
974
+ };
975
+ /**
976
+ * Expands a cell or range reference into an array of individual cell addresses.
977
+ *
978
+ * @param {string} cellRange - Single cell or `A1:B2`-style range (sheet token allowed).
979
+ * @returns {string} - Cell address array, or the original string when not expandable.
980
+ * @hidden
981
+ */
982
+ Calculate.prototype.getCellCollection = function (cellRange) {
983
+ if (cellRange.indexOf(':') < 0) {
984
+ if (!this.isCellReference(cellRange)) {
985
+ return cellRange.split(this.getParseArgumentSeparator());
986
+ }
987
+ else {
988
+ cellRange = cellRange + ':' + cellRange;
989
+ }
990
+ }
991
+ var token = '';
992
+ var sheetTokenIndex = cellRange.indexOf(this.sheetToken);
993
+ if (sheetTokenIndex > -1) {
994
+ var index = sheetTokenIndex;
995
+ var s = index + 1;
996
+ while (s < cellRange.length) {
997
+ if (cellRange[s] === this.sheetToken) {
998
+ token = cellRange.substr(0, s + 1);
999
+ break;
1000
+ }
1001
+ s++;
1002
+ }
1003
+ }
1004
+ var i = cellRange.indexOf(':');
1005
+ var row1;
1006
+ var row2;
1007
+ var col1;
1008
+ var col2;
1009
+ if (i > 0 && this.isChar(cellRange[i - 1])) {
1010
+ var k = i - 2;
1011
+ while (k >= 0 && this.isDigit(cellRange[k])) {
1012
+ k--;
1013
+ }
1014
+ }
1015
+ row1 = this.rowIndex(this.substring(cellRange, 0, i));
1016
+ row2 = this.rowIndex(this.substring(cellRange, i + 1, i + cellRange.length - i - 1));
1017
+ col1 = this.colIndex(this.substring(cellRange, 0, i));
1018
+ col2 = this.colIndex(this.substring(cellRange, i + 1, i + cellRange.length - i - 1));
1019
+ if (row1 >= maxRows || row2 >= maxRows || col1 >= maxCols || col2 >= maxCols) {
1020
+ return [this.getErrorStrings()[CommonErrors.Ref]];
1021
+ }
1022
+ if (row1 > row2) {
1023
+ i = row2;
1024
+ row2 = row1;
1025
+ row1 = i;
1026
+ }
1027
+ if (col1 > col2) {
1028
+ i = col2;
1029
+ col2 = col1;
1030
+ col1 = i;
1031
+ }
1032
+ var cells = [];
1033
+ var j;
1034
+ var c = 0;
1035
+ for (i = row1; i <= row2; i++) {
1036
+ for (j = col1; j <= col2; j++) {
1037
+ cells[c] = token + '' + this.convertAlpha(j) + i.toString();
1038
+ c++;
1039
+ }
1040
+ }
1041
+ return cells;
1042
+ };
1043
+ /**
1044
+ * Parses (when needed) and evaluates a formula expression.
1045
+ *
1046
+ * @hidden
1047
+ * @param {string} formulaText - Formula text (with or without leading `=`) or a pre-parsed token string.
1048
+ * @param {boolean} isFromComputeExpression - Internal flag when invoked from {@link computeExpression}.
1049
+ * @returns {string} - Computed value, or an Excel error token string on failure.
1050
+ *
1051
+ * @example
1052
+ * ```ts
1053
+ * engine.computeFormula('=SUM(1,2,3)'); // '6'
1054
+ * ```
1055
+ */
1056
+ Calculate.prototype.computeFormula = function (formulaText, isFromComputeExpression) {
1057
+ return this.calculateFormula(formulaText, false, isFromComputeExpression);
1058
+ };
1059
+ Calculate.prototype.calculateFormula = function (formulaText, refresh, isFromComputeExpression) {
1060
+ var _this = this;
1061
+ var parsedText;
1062
+ var lastIndexOfq;
1063
+ var formulatResult;
1064
+ var nestedFormula = false;
1065
+ var fNested;
1066
+ // Only short-circuit when a previously parsed formula is already marked as failed.
1067
+ // Fresh formula text must re-parse so one failure does not poison later computeFormula calls.
1068
+ if (this.parser.isError) {
1069
+ return formulaText;
1070
+ }
1071
+ if (!this.parser.isFormulaParsed) {
1072
+ parsedText = this.parser.parseFormula(formulaText);
1073
+ }
1074
+ else {
1075
+ parsedText = formulaText;
1076
+ }
1077
+ this.parser.isFormulaParsed = false;
1078
+ try {
1079
+ lastIndexOfq = this.findLastIndexOfq(parsedText);
1080
+ if (lastIndexOfq > 0) {
1081
+ nestedFormula = true;
1082
+ }
1083
+ if (parsedText !== '' && lastIndexOfq > -1) {
1084
+ var i = lastIndexOfq + 1;
1085
+ var _loop_1 = function () {
1086
+ if (parsedText[i] !== this_1.rightBracket) {
1087
+ i++;
1088
+ return "continue";
1089
+ }
1090
+ var sFormula = parsedText.substring(lastIndexOfq, i + 1);
1091
+ var libFormula = sFormula.split(this_1.leftBracket)[0].split('q').join('');
1092
+ var args = void 0;
1093
+ if (this_1.getLibraryFormulas().get(libFormula.toUpperCase()).isCustom) {
1094
+ args = sFormula.substring(sFormula.indexOf(this_1.leftBracket) + 1, sFormula.indexOf(this_1.rightBracket))
1095
+ .split(this_1.getParseArgumentSeparator());
1096
+ var j = 0;
1097
+ var customArgs = [];
1098
+ var cellCol = void 0;
1099
+ for (j = 0; j < args.length; j++) {
1100
+ if (args[j].includes(':') && this_1.isCellReference(args[j])) {
1101
+ cellCol = this_1.getCellCollection(args[j]);
1102
+ if (cellCol.length > 1) {
1103
+ customArgs.push(args[j]);
1104
+ cellCol.forEach(function (cell) {
1105
+ _this.updateDependentCell(cell);
1106
+ });
1107
+ }
1108
+ else {
1109
+ customArgs.push(this_1.getValueFromArg(args[j]));
1110
+ }
1111
+ }
1112
+ else {
1113
+ customArgs.push(this_1.getValueFromArg(args[j]));
1114
+ }
1115
+ }
1116
+ args = customArgs;
1117
+ }
1118
+ else {
1119
+ var argStr = sFormula.substring(sFormula.indexOf(this_1.leftBracket) + 1, sFormula.indexOf(this_1.rightBracket));
1120
+ args = [];
1121
+ var separator = this_1.getParseArgumentSeparator();
1122
+ var parameter = '';
1123
+ var isInString = void 0;
1124
+ for (var idx = 0, len = argStr.length - 1; idx <= len; idx++) {
1125
+ if (argStr[idx] === '"') {
1126
+ isInString = !isInString;
1127
+ }
1128
+ if (argStr[idx] === separator && !isInString) {
1129
+ args.push(parameter);
1130
+ parameter = '';
1131
+ if (idx === len) {
1132
+ args.push(parameter);
1133
+ }
1134
+ }
1135
+ else {
1136
+ parameter += argStr[idx];
1137
+ if (idx === len) {
1138
+ args.push(parameter);
1139
+ }
1140
+ }
1141
+ }
1142
+ if (!args.length) {
1143
+ args = [''];
1144
+ }
1145
+ if (nestedFormula && libFormula) {
1146
+ var formulas = ['IF', 'INDEX', 'SORT', 'T', 'EXACT',
1147
+ 'PROPER', 'DOLLAR', 'DATE', 'TEXT', 'ISNUMBER'];
1148
+ if (formulas.some(function (formula) { return formula === libFormula; })) {
1149
+ args.push('nestedFormulaTrue');
1150
+ }
1151
+ if (libFormula === 'IF') {
1152
+ args.push('nestedFormulaTrue');
1153
+ }
1154
+ if (libFormula === 'VLOOKUP' || libFormula === 'HLOOKUP') {
1155
+ var parentQIdx = parsedText.lastIndexOf('q', lastIndexOfq - 1);
1156
+ if (parentQIdx !== -1) {
1157
+ var formula_1 = parsedText.substring(parentQIdx + 1, parsedText.lastIndexOf(this_1.leftBracket, lastIndexOfq - 1));
1158
+ var conditionalFormulas = ['IF', 'IFS', 'AND', 'OR', 'NOT'];
1159
+ if (conditionalFormulas.some(function (cFormula) { return cFormula === formula_1; })) {
1160
+ args.push('conditionalFormulaTrue');
1161
+ }
1162
+ }
1163
+ }
1164
+ }
1165
+ if (isFromComputeExpression && libFormula === 'UNIQUE') {
1166
+ args.push('isComputeExp');
1167
+ }
1168
+ }
1169
+ formulatResult = isNullOrUndefined(this_1.getFunction(libFormula)) ? this_1.getErrorStrings()[CommonErrors.Name] : this_1.getFunction(libFormula).apply(void 0, args);
1170
+ if (nestedFormula) {
1171
+ fNested = this_1.processNestedFormula(parsedText, sFormula, formulatResult);
1172
+ var q = this_1.findLastIndexOfq(fNested);
1173
+ if (q === 0) {
1174
+ nestedFormula = false;
1175
+ }
1176
+ if (q === -1) {
1177
+ formulatResult = this_1.computeValue(fNested, refresh);
1178
+ }
1179
+ lastIndexOfq = i = q;
1180
+ parsedText = fNested;
1181
+ return "continue";
1182
+ }
1183
+ return "break";
1184
+ };
1185
+ var this_1 = this;
1186
+ while (i > -1) {
1187
+ var state_1 = _loop_1();
1188
+ if (state_1 === "break")
1189
+ break;
1190
+ }
1191
+ }
1192
+ else if (this.formulaErrorStrings.indexOf(parsedText) > -1) {
1193
+ formulatResult = parsedText;
1194
+ }
1195
+ else if (parsedText !== '' && lastIndexOfq === -1) {
1196
+ formulatResult = this.computeValue(parsedText, refresh);
1197
+ }
1198
+ }
1199
+ catch (ex) {
1200
+ var args = { message: ex.message, exception: ex, isForceCalculable: false, computeForceCalculate: false };
1201
+ this.trigger('onFailure', args);
1202
+ var errorMessage = (typeof args.exception === 'string') ? args.exception : args.message;
1203
+ formulatResult = (isNullOrUndefined(this.getErrorLine(ex)) ? '' : '#' + this.getErrorLine(ex) + ': ') + errorMessage;
1204
+ }
1205
+ return formulatResult;
1206
+ };
1207
+ /**
1208
+ * Shared implementation for SUMIF / AVERAGEIF range evaluation.
1209
+ *
1210
+ * @param {string} range - Argument tokens for the conditional aggregate.
1211
+ * @param {boolean} isAvgIf - When `true`, computes AVERAGEIF semantics; otherwise SUMIF.
1212
+ * @returns {string} - Partial aggregate values or an error string.
1213
+ * @hidden
1214
+ */
1215
+ Calculate.prototype.computeSumIfAndAvgIf = function (range, isAvgIf) {
1216
+ if (isNullOrUndefined(range) || range[0] === '' || range.length === 0) {
1217
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
1218
+ }
1219
+ var argArr = range;
1220
+ for (var i = 0; i < argArr.length; i++) {
1221
+ if (this.isCellReference(argArr[i]) && isNullOrUndefined(argArr[i].match(/[0-9]/)) &&
1222
+ argArr[i].indexOf('!') < 0) {
1223
+ var splitArray = argArr[i].split(':');
1224
+ argArr[i] = splitArray[0] + '1' + ':' + splitArray[1] + this.spreadSheetUsedRange[0];
1225
+ }
1226
+ }
1227
+ var argCount = argArr.length;
1228
+ if (argCount !== 2 && argCount !== 3 && argCount === 0) {
1229
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
1230
+ }
1231
+ if (argArr[1] === '') {
1232
+ return isAvgIf ? this.getErrorStrings()[CommonErrors.DivZero] : '0';
1233
+ }
1234
+ var rangevalue = argArr[0];
1235
+ var isStringVal = argArr[1].startsWith(this.tic) && argArr[1].endsWith(this.tic);
1236
+ var criteria = this.getANDComputedValue(argArr[1]);
1237
+ if (criteria.length > 255) {
1238
+ return this.getErrorStrings()[CommonErrors.Value];
1239
+ }
1240
+ var isAsterisk = criteria.includes('*');
1241
+ var isQuestionMark = criteria.includes('?');
1242
+ var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '').trim() : criteria;
1243
+ var isCellReferenceValue = false;
1244
+ if (!isStringVal && this.isCellReference(criteriaValue)) {
1245
+ criteriaValue = this.getValueFromArg(criteriaValue);
1246
+ isCellReferenceValue = true;
1247
+ }
1248
+ if (isAsterisk) {
1249
+ var asteriskIndex = criteria.indexOf('*');
1250
+ if (criteria[0] === '*') {
1251
+ criteriaValue = '*' + criteriaValue;
1252
+ }
1253
+ if (criteria[criteria.length - 1] === '*') {
1254
+ criteriaValue += '*';
1255
+ }
1256
+ if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
1257
+ criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
1258
+ }
1259
+ }
1260
+ criteria = criteriaValue;
1261
+ var opt = this.parser.tokenEqual;
1262
+ if (criteria.startsWith('<=')) {
1263
+ opt = this.parser.tokenLessEq;
1264
+ criteria = criteria.substring(2);
1265
+ }
1266
+ else if (criteria.startsWith('>=')) {
1267
+ opt = this.parser.tokenGreaterEq;
1268
+ criteria = criteria.substring(2);
1269
+ }
1270
+ else if (criteria.startsWith('<>')) {
1271
+ opt = this.parser.tokenNotEqual;
1272
+ criteria = criteria.substring(2);
1273
+ }
1274
+ else if (criteria.startsWith('<')) {
1275
+ opt = this.parser.tokenLess;
1276
+ criteria = criteria.substring(1);
1277
+ }
1278
+ else if (criteria.startsWith('>')) {
1279
+ opt = this.parser.tokenGreater;
1280
+ criteria = criteria.substring(1);
1281
+ }
1282
+ else if (criteria.startsWith('=')) {
1283
+ opt = this.parser.tokenEqual;
1284
+ criteria = criteria.substring(1);
1285
+ }
1286
+ if ((!isStringVal && this.isCellReference(criteria) && !isCellReferenceValue) || criteria.includes(this.arithMarker) ||
1287
+ (criteria.includes(this.getParseDecimalSeparator()) && !isAsterisk && !isQuestionMark)) {
1288
+ criteria = this.getValueFromArg(criteria);
1289
+ }
1290
+ var checkCriteria = this.parseFloat(criteria);
1291
+ var criteriaRangeArray = argArr[0];
1292
+ var sumRange = this.getCellCollection(argCount > 2 ? argArr[2] : rangevalue);
1293
+ var criteriaRange = this.getCellCollection(criteriaRangeArray);
1294
+ if (sumRange[0] === '#REF!' || criteriaRange[0] === '#REF!') {
1295
+ return this.getErrorStrings()[CommonErrors.Name];
1296
+ }
1297
+ if (criteriaRange.length > sumRange.length) {
1298
+ var sumEndCol = this.colIndex(sumRange[sumRange.length - 1]) +
1299
+ this.colIndex(criteriaRange[criteriaRange.length - 1]) - this.colIndex(criteriaRange[0]);
1300
+ var sumrange = argArr[2].split(':');
1301
+ sumrange[1] = (this.convertAlpha(sumEndCol) + this.rowIndex(criteriaRange[criteriaRange.length - 1])).toString();
1302
+ sumRange = this.getCellCollection(sumrange.join(':'));
1303
+ if (sumRange[0] === '#REF!') {
1304
+ return this.getErrorStrings()[CommonErrors.Name];
1305
+ }
1306
+ }
1307
+ var result = this.getComputeSumIfValue(criteriaRange, sumRange, criteria.toLowerCase(), checkCriteria, opt, isAsterisk, isQuestionMark);
1308
+ return [result[0], result[1]];
1309
+ };
1310
+ /**
1311
+ * Shared LOOKUP evaluation helper used by library formula handlers.
1312
+ *
1313
+ * @param {string} range - LOOKUP argument tokens.
1314
+ * @returns {string} - Matched value or an error token.
1315
+ * @hidden
1316
+ */
1317
+ Calculate.prototype.computeLookup = function (range) {
1318
+ var _a, _b;
1319
+ var lookupArray;
1320
+ var matchArray;
1321
+ var lookupRange = [];
1322
+ var matchupRange = [];
1323
+ var checkCriteria = [];
1324
+ var findMaxVal = [];
1325
+ var lookupValue;
1326
+ var isArrayVector;
1327
+ var result = [];
1328
+ var argArr = range;
1329
+ var argCount = argArr.length;
1330
+ if (argCount === 1 || argCount > 3) {
1331
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
1332
+ }
1333
+ if (argArr[1] === '' || argArr[2] === '') {
1334
+ return this.getErrorStrings()[CommonErrors.Value];
1335
+ }
1336
+ lookupValue = this.getValueFromArg(argArr[0]);
1337
+ if (argArr[0].indexOf(this.tic) > -1 && argArr[0].toUpperCase().split(this.tic).join('') !== this.trueValue &&
1338
+ argArr[0].toUpperCase().split(this.tic).join('') !== this.falseValue && this.isNaN(this.parseFloat(argArr[0].split(this.tic).join('')))) {
1339
+ lookupValue = lookupValue.split(this.tic).join('');
1340
+ }
1341
+ if (this.getErrorStrings().indexOf(lookupValue) > -1) {
1342
+ return lookupValue;
1343
+ }
1344
+ var rangeSplit = argArr[1].split(':');
1345
+ if (rangeSplit.length === 2 && this.isCellReference(rangeSplit[0]) && this.isCellReference(rangeSplit[1]) && argCount === 2) {
1346
+ var index = argArr[1].indexOf(':');
1347
+ var rowIdx = this.rowIndex(this.substring(argArr[1], 0, index));
1348
+ var colIdx = this.colIndex(this.substring(argArr[1], 0, index));
1349
+ var endRowIdx = this.rowIndex(this.substring(argArr[1], index + 1, index + argArr[1].length - index - 1));
1350
+ var endColIdx = this.colIndex(this.substring(argArr[1], index + 1, index + argArr[1].length - index - 1));
1351
+ if (rowIdx > endRowIdx) {
1352
+ _a = [endRowIdx, rowIdx], rowIdx = _a[0], endRowIdx = _a[1];
1353
+ }
1354
+ if (colIdx > endColIdx) {
1355
+ _b = [endColIdx, colIdx], colIdx = _b[0], endColIdx = _b[1];
1356
+ }
1357
+ var sheetIdx = '';
1358
+ if (argArr[1].indexOf('!') === 0) {
1359
+ sheetIdx = argArr[1];
1360
+ sheetIdx = sheetIdx.replace('!', '');
1361
+ sheetIdx = sheetIdx.indexOf('!');
1362
+ sheetIdx = argArr[1].substring(0, sheetIdx + 2);
1363
+ }
1364
+ var colCount = endColIdx - colIdx + 1;
1365
+ var rowCount = endRowIdx - rowIdx + 1;
1366
+ if (rowCount > colCount || rowCount === colCount) { // Taller than Wide. vlookup
1367
+ lookupArray = sheetIdx + getAlphalabel(colIdx) + rowIdx + ':' + getAlphalabel(colIdx) + endRowIdx;
1368
+ matchArray = sheetIdx + getAlphalabel(endColIdx) + rowIdx + ':' + getAlphalabel(endColIdx) + endRowIdx;
1369
+ }
1370
+ else if (rowCount < colCount) { // Wider than Tall. hlookup
1371
+ lookupArray = sheetIdx + getAlphalabel(colIdx) + rowIdx + ':' + getAlphalabel(endColIdx) + rowIdx;
1372
+ matchArray = sheetIdx + getAlphalabel(colIdx) + endRowIdx + ':' + getAlphalabel(endColIdx) + endRowIdx;
1373
+ }
1374
+ if (rowIdx !== endRowIdx || colIdx !== endColIdx) {
1375
+ isArrayVector = true;
1376
+ }
1377
+ }
1378
+ if (isArrayVector) {
1379
+ lookupRange = this.getCellCollection(lookupArray);
1380
+ matchupRange = this.getCellCollection(matchArray);
1381
+ if (lookupRange[0] === '#REF!' || matchupRange[0] === '#REF!') {
1382
+ return this.getErrorStrings()[CommonErrors.Name];
1383
+ }
1384
+ }
1385
+ else {
1386
+ lookupRange = this.getCellCollection(argArr[1]);
1387
+ var arrvalue = argCount === 2 ? argArr[1] : argArr[2];
1388
+ matchupRange = this.getCellCollection(arrvalue);
1389
+ if (lookupRange[0] === '#REF!' || matchupRange[0] === '#REF!') {
1390
+ return this.getErrorStrings()[CommonErrors.Name];
1391
+ }
1392
+ var lookupIndex = getRangeIndexes(argArr[1]);
1393
+ var matchIndex = getRangeIndexes(arrvalue);
1394
+ var isValidLookup = lookupIndex[1] === lookupIndex[3] ? true : lookupIndex[0] === lookupIndex[2];
1395
+ var isValidMatch = matchIndex[1] === matchIndex[3] ? true : matchIndex[0] === matchIndex[2];
1396
+ if (!isValidLookup || !isValidMatch) {
1397
+ return this.getErrorStrings()[CommonErrors.NA];
1398
+ }
1399
+ }
1400
+ for (var i = 0; i < lookupRange.length; i++) {
1401
+ findMaxVal.push(this.getValueFromArg(lookupRange[i]).split(this.tic).join(''));
1402
+ }
1403
+ var num = findMaxVal.map(function (value) { return value === '' ? NaN : Number(value); }).sort(function (a, b) { return a - b; });
1404
+ var maxVal = num[num.length - 1];
1405
+ var minVal = num[0];
1406
+ var lookupVal = this.parseFloat(lookupValue);
1407
+ if (!this.isNaN(lookupVal)) {
1408
+ for (var a = 0; a < num.length; a++) {
1409
+ checkCriteria[a] = num[a].toString().split(this.tic).join('');
1410
+ if (!isNullOrUndefined(matchupRange[a]) && checkCriteria[a] !== '' && lookupVal === this.parseFloat(checkCriteria[a])) {
1411
+ result.push(this.getValueFromArg(matchupRange[a]).split(this.tic).join('') || '0');
1412
+ }
1413
+ }
1414
+ }
1415
+ else {
1416
+ for (var j = 0; j < lookupRange.length; j++) {
1417
+ checkCriteria[j] = this.getValueFromArg(lookupRange[j]).split(this.tic).join('');
1418
+ if (!isNullOrUndefined(matchupRange[j]) && lookupValue !== '' && checkCriteria[j] !== '') {
1419
+ if (lookupValue.toUpperCase() === checkCriteria[j].toUpperCase()) {
1420
+ result.push(this.getValueFromArg(matchupRange[j]).split(this.tic).join('') || '0');
1421
+ }
1422
+ else if (lookupValue.indexOf('*') > -1 || lookupValue.indexOf('?') > -1) {
1423
+ var criteriaValue = lookupValue;
1424
+ if (lookupValue.indexOf('*') > -1) {
1425
+ criteriaValue = criteriaValue.replace(/\*/g, '').trim();
1426
+ if (this.isCellReference(criteriaValue)) {
1427
+ criteriaValue = this.getValueFromArg(criteriaValue);
1428
+ }
1429
+ var asteriskIndex = lookupValue.indexOf('*');
1430
+ if (lookupValue[0] === '*') {
1431
+ criteriaValue = '*' + criteriaValue;
1432
+ }
1433
+ if (lookupValue[lookupValue.length - 1] === '*') {
1434
+ criteriaValue += '*';
1435
+ }
1436
+ if (asteriskIndex > 0 && asteriskIndex < lookupValue.length - 1) {
1437
+ criteriaValue = lookupValue.substring(0, asteriskIndex) + '*' + lookupValue.substring(asteriskIndex + 1);
1438
+ }
1439
+ }
1440
+ var stack = [];
1441
+ var wildcardResult = this.findWildCardValue(criteriaValue.toLowerCase(), checkCriteria[j].toLowerCase());
1442
+ stack.push(wildcardResult);
1443
+ stack.push(lookupValue);
1444
+ if (this.processLogical(stack, 'equal') === this.trueValue) {
1445
+ result.push(this.getValueFromArg(matchupRange[j]).split(this.tic).join('') || '0');
1446
+ }
1447
+ }
1448
+ }
1449
+ }
1450
+ }
1451
+ if (result.length > 0) {
1452
+ return result[result.length - 1];
1453
+ }
1454
+ if (lookupVal > maxVal && !isNullOrUndefined(matchupRange[lookupRange.length - 1])) {
1455
+ return this.getValueFromArg(matchupRange[lookupRange.length - 1]).split(this.tic).join('') || '0';
1456
+ }
1457
+ else if (lookupVal < minVal) {
1458
+ return this.getErrorStrings()[CommonErrors.NA];
1459
+ }
1460
+ if (findMaxVal.indexOf(lookupValue.split(this.tic).join('')) < 0 && lookupValue !== this.trueValue && lookupValue !== this.falseValue) {
1461
+ if (!this.isNaN(lookupVal) && !this.isNaN(maxVal) && !this.isNaN(minVal)) {
1462
+ var temp = [];
1463
+ for (var b = 0; b < num.length; b++) {
1464
+ if (lookupVal > num[b]) {
1465
+ temp.push(num[b]);
1466
+ }
1467
+ }
1468
+ var index = temp.length - 1;
1469
+ if (!isNullOrUndefined(matchupRange[index]) && index >= 0) {
1470
+ return this.getValueFromArg(matchupRange[index]).split(this.tic).join('') || '0';
1471
+ }
1472
+ }
1473
+ else if (this.isNaN(lookupVal) && lookupValue !== '' && /^[a-zA-Z!@#$%^&*()_+{}[\]:;<>,.?~\\/-]/.test(lookupValue)) {
1474
+ var str = findMaxVal.sort();
1475
+ var index = this.findClosestMatch(lookupValue.split(this.tic).join(''), str);
1476
+ if (!isNullOrUndefined(matchupRange[index]) && index >= 0) {
1477
+ return this.getValueFromArg(matchupRange[index]).split(this.tic).join('') || '0';
1478
+ }
1479
+ }
1480
+ }
1481
+ return this.getErrorStrings()[CommonErrors.NA];
1482
+ };
1483
+ /**
1484
+ * Shared VLOOKUP / HLOOKUP evaluation helper.
1485
+ *
1486
+ * @param {string} range - Lookup argument tokens.
1487
+ * @param {boolean} isVlookup - When `true` (default), uses VLOOKUP orientation; otherwise HLOOKUP.
1488
+ * @returns {string} - Matched value or an error token.
1489
+ * @hidden
1490
+ */
1491
+ Calculate.prototype.computeVHLookup = function (range, isVlookup) {
1492
+ var _this = this;
1493
+ var _a, _b;
1494
+ var argArr = range;
1495
+ var isConditionalFormula;
1496
+ if (argArr && argArr[argArr.length - 1] === 'conditionalFormulaTrue') {
1497
+ isConditionalFormula = true;
1498
+ argArr.pop();
1499
+ }
1500
+ if (isNullOrUndefined(argArr) || argArr.length < 3 || argArr.length > 4) {
1501
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
1502
+ }
1503
+ if (argArr[1] === '') {
1504
+ return this.getErrorStrings()[CommonErrors.NA];
1505
+ }
1506
+ var lookupValue = this.getValueFromArg(argArr[0]);
1507
+ if (lookupValue) {
1508
+ if (lookupValue.includes(this.tic)) {
1509
+ var lookupVal = lookupValue.split(this.tic).join('');
1510
+ if (lookupVal && !this.isNumber(lookupVal)) {
1511
+ var lookupValUpper = lookupVal.toUpperCase();
1512
+ if (lookupValUpper !== this.trueValue && lookupValUpper !== this.falseValue) {
1513
+ lookupValue = lookupVal;
1514
+ }
1515
+ }
1516
+ }
1517
+ }
1518
+ else {
1519
+ lookupValue = '0';
1520
+ }
1521
+ var errorStrings = this.getErrorStrings();
1522
+ if (errorStrings.indexOf(lookupValue) > -1) {
1523
+ return lookupValue;
1524
+ }
1525
+ var colIdxVal = (this.getValueFromArg(argArr[2]) || '0').split(this.tic).join('').toUpperCase();
1526
+ var colNumIdx = this.parseFloat(colIdxVal === this.trueValue ? '1' : colIdxVal);
1527
+ if (colNumIdx < 1) {
1528
+ return errorStrings[CommonErrors.Value];
1529
+ }
1530
+ var isExactMatchLookup;
1531
+ if (argArr[3]) {
1532
+ argArr[3] = this.getValueFromArg(argArr[3]).split(this.tic).join('');
1533
+ if (errorStrings.indexOf(argArr[3]) > -1) {
1534
+ return argArr[3];
1535
+ }
1536
+ var rangeLookup = argArr[3].toUpperCase();
1537
+ if (rangeLookup === this.falseValue || argArr[3] === '0') {
1538
+ isExactMatchLookup = true;
1539
+ }
1540
+ else if (!(rangeLookup === this.trueValue || argArr[3] === '1')) {
1541
+ return errorStrings[CommonErrors.Value];
1542
+ }
1543
+ }
1544
+ var rangeArr = argArr[1].split(':');
1545
+ var startIdx;
1546
+ var endIdx;
1547
+ var idx;
1548
+ var grid;
1549
+ var getLookupRangeValue;
1550
+ var getMatchRangeValue;
1551
+ if (this.isCellReference(rangeArr[0]) && this.isCellReference(rangeArr[1])) {
1552
+ var rowIdx_1 = this.rowIndex(rangeArr[0]);
1553
+ var colIdx_1 = this.colIndex(rangeArr[0]);
1554
+ var endRowIdx = this.rowIndex(rangeArr[1]);
1555
+ var endColIdx = this.colIndex(rangeArr[1]);
1556
+ if (rowIdx_1 > endRowIdx) {
1557
+ _a = [endRowIdx, rowIdx_1], rowIdx_1 = _a[0], endRowIdx = _a[1];
1558
+ }
1559
+ if (colIdx_1 > endColIdx) {
1560
+ _b = [endColIdx, colIdx_1], colIdx_1 = _b[0], endColIdx = _b[1];
1561
+ }
1562
+ if (!(rowIdx_1 > 0 && endRowIdx <= maxRows && colIdx_1 > 0 && endColIdx <= maxCols)) {
1563
+ return this.getErrorStrings()[CommonErrors.Name];
1564
+ }
1565
+ grid = this.grid;
1566
+ var sheetToken_1 = '';
1567
+ var family = this.getSheetFamilyItem(grid);
1568
+ if (argArr[1].startsWith('!')) {
1569
+ sheetToken_1 = argArr[1].substring(0, argArr[1].replace('!', '').indexOf('!') + 2);
1570
+ if (family.tokenToParentObject !== null) {
1571
+ this.grid = family.tokenToParentObject.get(sheetToken_1);
1572
+ }
1573
+ }
1574
+ else if (family.parentObjectToToken !== null) {
1575
+ sheetToken_1 = family.parentObjectToToken.get(grid);
1576
+ }
1577
+ var sheetId = this.getSheetId(this.grid);
1578
+ var sheetInfo = this.getHostSheetInfo();
1579
+ if (getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
1580
+ this.grid = grid;
1581
+ return errorStrings[CommonErrors.Ref];
1582
+ }
1583
+ var getCellValue_1 = this.getCellValueFn(grid, this.cell, sheetId, true);
1584
+ if (isVlookup) {
1585
+ var matchIndex_1 = colIdx_1 + colNumIdx - 1;
1586
+ if (matchIndex_1 > endColIdx) {
1587
+ return errorStrings[CommonErrors.Ref];
1588
+ }
1589
+ startIdx = rowIdx_1;
1590
+ endIdx = endRowIdx;
1591
+ var lookupColText_1 = sheetToken_1 + getAlphalabel(colIdx_1);
1592
+ getLookupRangeValue = function (idx) {
1593
+ return getCellValue_1(idx, colIdx_1, lookupColText_1 + idx);
1594
+ };
1595
+ var matchColText_1 = sheetToken_1 + getAlphalabel(matchIndex_1);
1596
+ getMatchRangeValue = function () {
1597
+ return getCellValue_1(idx, matchIndex_1, matchColText_1 + idx) || (isConditionalFormula ? '""' : '0');
1598
+ };
1599
+ }
1600
+ else {
1601
+ var matchIndex_2 = rowIdx_1 + colNumIdx - 1;
1602
+ if (matchIndex_2 > endRowIdx) {
1603
+ return errorStrings[CommonErrors.Ref];
1604
+ }
1605
+ startIdx = colIdx_1;
1606
+ endIdx = endColIdx;
1607
+ var matchColText_2;
1608
+ getLookupRangeValue = function (idx) {
1609
+ matchColText_2 = sheetToken_1 + getAlphalabel(idx);
1610
+ return getCellValue_1(rowIdx_1, idx, matchColText_2 + rowIdx_1);
1611
+ };
1612
+ getMatchRangeValue = function () {
1613
+ return getCellValue_1(matchIndex_2, idx, matchColText_2 + matchIndex_2) || (isConditionalFormula ? '""' : '0');
1614
+ };
1615
+ }
1616
+ }
1617
+ else {
1618
+ return errorStrings[CommonErrors.Value];
1619
+ }
1620
+ var result;
1621
+ var lookupRangeVal;
1622
+ var matchedResult = [];
1623
+ if (isExactMatchLookup) {
1624
+ var isMatchFound = void 0;
1625
+ if (this.isNumber(lookupValue)) {
1626
+ var lookupNumVal_1 = this.parseFloat(lookupValue);
1627
+ isMatchFound = function () {
1628
+ return lookupNumVal_1 === _this.parseFloat(lookupRangeVal);
1629
+ };
1630
+ }
1631
+ else if (lookupValue.includes('*') || lookupValue.includes('?')) {
1632
+ var criteriaValue_1 = lookupValue;
1633
+ var asteriskIndex = lookupValue.indexOf('*');
1634
+ if (asteriskIndex > -1) {
1635
+ criteriaValue_1 = criteriaValue_1.replace(/\*/g, '').trim();
1636
+ if (this.isCellReference(criteriaValue_1)) {
1637
+ criteriaValue_1 = this.getValueFromArg(criteriaValue_1);
1638
+ }
1639
+ if (asteriskIndex === 0) {
1640
+ criteriaValue_1 = '*' + criteriaValue_1;
1641
+ }
1642
+ else if (asteriskIndex === lookupValue.length - 1) {
1643
+ criteriaValue_1 += '*';
1644
+ }
1645
+ else {
1646
+ criteriaValue_1 = lookupValue.substring(0, asteriskIndex) + '*' + lookupValue.substring(asteriskIndex + 1);
1647
+ }
1648
+ }
1649
+ criteriaValue_1 = criteriaValue_1.toLowerCase();
1650
+ isMatchFound = function () {
1651
+ return _this.processLogical([_this.findWildCardValue(criteriaValue_1, lookupRangeVal.toLowerCase()), lookupValue], 'equal') === _this.trueValue;
1652
+ };
1653
+ }
1654
+ else {
1655
+ var lookupValUpper_1 = lookupValue.toUpperCase();
1656
+ isMatchFound = function () {
1657
+ return lookupValUpper_1 === lookupRangeVal.toUpperCase();
1658
+ };
1659
+ }
1660
+ for (idx = startIdx; idx <= endIdx; idx++) {
1661
+ lookupRangeVal = getLookupRangeValue(idx);
1662
+ if (lookupRangeVal && isMatchFound()) {
1663
+ matchedResult.push(getMatchRangeValue());
1664
+ }
1665
+ }
1666
+ result = matchedResult.length ? matchedResult[0] : errorStrings[CommonErrors.NA];
1667
+ }
1668
+ else if (lookupValue.indexOf('*') > -1 || lookupValue.indexOf('?') > -1) {
1669
+ result = errorStrings[CommonErrors.NA];
1670
+ }
1671
+ else {
1672
+ var matchVal_1;
1673
+ var checkMatchFn = void 0;
1674
+ if (this.isNumber(lookupValue)) {
1675
+ var lookupNumVal_2 = this.parseFloat(lookupValue);
1676
+ var comparer_1 = createSortComparer('');
1677
+ checkMatchFn = function () {
1678
+ matchVal_1 = comparer_1(_this.isNumber(lookupRangeVal) ? _this.parseFloat(lookupRangeVal) : lookupRangeVal || null, lookupNumVal_2);
1679
+ };
1680
+ }
1681
+ else {
1682
+ var collator_1 = new Intl.Collator(this.parentObject.locale || 'en-US', { sensitivity: 'base' });
1683
+ checkMatchFn = function () {
1684
+ matchVal_1 = (!lookupRangeVal || _this.isNumber(lookupRangeVal)) ? null : collator_1.compare(lookupRangeVal, lookupValue);
1685
+ };
1686
+ }
1687
+ var skipCheck = void 0;
1688
+ for (idx = startIdx; idx <= endIdx; idx++) {
1689
+ lookupRangeVal = getLookupRangeValue(idx);
1690
+ if (!skipCheck) {
1691
+ checkMatchFn();
1692
+ if (matchVal_1 === 0) {
1693
+ matchedResult.push(getMatchRangeValue());
1694
+ }
1695
+ else if (matchVal_1 < 0) {
1696
+ matchedResult.push(getMatchRangeValue());
1697
+ }
1698
+ else if (matchVal_1 > 0 && matchedResult.length) {
1699
+ skipCheck = true;
1700
+ }
1701
+ }
1702
+ }
1703
+ result = matchedResult.length ? matchedResult[matchedResult.length - 1] : errorStrings[CommonErrors.NA];
1704
+ }
1705
+ this.grid = grid;
1706
+ if (isConditionalFormula && typeof result === 'string' &&
1707
+ result.indexOf(this.getParseArgumentSeparator()) !== -1) {
1708
+ return this.tic + result + this.tic;
1709
+ }
1710
+ return result;
1711
+ };
1712
+ Calculate.prototype.findClosestMatch = function (searchValue, sortedArray) {
1713
+ var start = 0;
1714
+ var end = sortedArray.length - 1;
1715
+ while (start <= end) {
1716
+ var mid = Math.floor((start + end) / 2);
1717
+ var midValue = sortedArray[mid];
1718
+ var compareResult = this.compareStrings(searchValue.toLowerCase(), midValue.toLowerCase());
1719
+ if (compareResult === 0) {
1720
+ return mid;
1721
+ }
1722
+ else if (compareResult === 1) {
1723
+ start = mid + 1;
1724
+ }
1725
+ else {
1726
+ end = mid - 1;
1727
+ }
1728
+ }
1729
+ // If no exact match is found, return the closest match based on the entire string
1730
+ for (var i = start - 1; i >= 0; i--) {
1731
+ if (this.compareStrings(searchValue.toLowerCase(), sortedArray[i].toLowerCase()) !== -1) {
1732
+ return i;
1733
+ }
1734
+ }
1735
+ return -1; // No match found
1736
+ };
1737
+ Calculate.prototype.compareStrings = function (str1, str2) {
1738
+ var minLength = Math.min(str1.length, str2.length);
1739
+ for (var i = 0; i < minLength; i++) {
1740
+ var charCode1 = str1.charCodeAt(i);
1741
+ var charCode2 = str2.charCodeAt(i);
1742
+ if (charCode1 < charCode2) {
1743
+ return -1;
1744
+ }
1745
+ else if (charCode1 > charCode2) {
1746
+ return 1;
1747
+ }
1748
+ }
1749
+ // If all characters are the same up to the length of the shorter string, compare lengths
1750
+ if (str1.length < str2.length) {
1751
+ return -1;
1752
+ }
1753
+ else if (str1.length > str2.length) {
1754
+ return 1;
1755
+ }
1756
+ else {
1757
+ return 0;
1758
+ }
1759
+ };
1760
+ /**
1761
+ * Applies Excel-style wildcard matching (`*`, `?`, `~`) between criteria and a cell value.
1762
+ *
1763
+ * @param {string | number | Object} lookVal - Criteria pattern.
1764
+ * @param {string} cellValue - Candidate cell text.
1765
+ * @returns {string | number} - Match marker or original values used by lookup/criteria helpers.
1766
+ * @hidden
1767
+ */
1768
+ Calculate.prototype.findWildCardValue = function (lookVal, cellValue) {
1769
+ var finalText = '';
1770
+ if (lookVal.indexOf('?') > -1) {
1771
+ var checkRegex = RegExp(lookVal.replace(/\?/g, '[\\s\\S]'));
1772
+ if (cellValue.length === lookVal.length && this.isNaN(this.parseFloat(cellValue))) {
1773
+ if (cellValue.match(checkRegex)) {
1774
+ finalText = lookVal;
1775
+ }
1776
+ else {
1777
+ finalText = cellValue;
1778
+ }
1779
+ }
1780
+ else {
1781
+ finalText = cellValue;
1782
+ }
1783
+ }
1784
+ else if (lookVal.indexOf('*') > -1) {
1785
+ var index = lookVal.indexOf('*');
1786
+ var left = '';
1787
+ var right = '';
1788
+ var compRight = this.falseValue;
1789
+ var compLeft = this.falseValue;
1790
+ for (var i = index - 1; i >= 0; i--) {
1791
+ left = left + lookVal[i];
1792
+ compLeft = this.trueValue;
1793
+ }
1794
+ for (var i = index + 1; i < lookVal.length; i++) {
1795
+ right = right + lookVal[i];
1796
+ compRight = this.trueValue;
1797
+ }
1798
+ var leftVal = left === '' ? -1 : cellValue.indexOf(left.split('').reverse().join(''));
1799
+ var rightVal = right === '' ? -1 : cellValue.indexOf(right);
1800
+ if (leftVal > -1 || rightVal > -1) {
1801
+ var isLeft = left.split('').reverse().join('') === cellValue.substr(0, left.length);
1802
+ var isRight = right === cellValue.substring(cellValue.length - right.length, cellValue.length);
1803
+ if (compLeft === this.trueValue && compRight === this.trueValue &&
1804
+ this.isNaN(this.parseFloat(left)) && this.isNaN(this.parseFloat(right))) {
1805
+ finalText = isLeft && isRight ? lookVal : cellValue;
1806
+ }
1807
+ else if (compLeft === this.trueValue && this.isNaN(this.parseFloat(left))) {
1808
+ finalText = isLeft ? lookVal : cellValue;
1809
+ }
1810
+ else if (compRight === this.trueValue && this.isNaN(this.parseFloat(right))) {
1811
+ finalText = isRight ? lookVal : cellValue;
1812
+ }
1813
+ }
1814
+ else {
1815
+ if (lookVal.startsWith('*') && lookVal.endsWith('*')) {
1816
+ var trimmedVal = lookVal.slice(1, -1);
1817
+ if (trimmedVal !== '' && cellValue.includes(trimmedVal) && this.isNaN(this.parseFloat(trimmedVal))) {
1818
+ cellValue = lookVal;
1819
+ }
1820
+ }
1821
+ finalText = cellValue;
1822
+ }
1823
+ }
1824
+ return finalText;
1825
+ };
1826
+ /**
1827
+ * Evaluates criteria against a criteria range and aggregates matching sum-range values.
1828
+ *
1829
+ * @param {string} criteriaRange - Criteria cells.
1830
+ * @param {string} sumRange - Values to aggregate for matches.
1831
+ * @param {string} criteria - Criteria expression.
1832
+ * @returns {string | number} - Aggregate result details used by SUMIF-family formulas.
1833
+ * @hidden
1834
+ */
1835
+ Calculate.prototype.getComputeSumIfValue = function (criteriaRange, sumRange, criteria, checkCriteria, op, isAsterisk, isQuestionMark) {
1836
+ var sum = 0;
1837
+ var count = 0;
1838
+ // const isFirst: boolean = isAsterisk && criteria && criteria[0] === '*';
1839
+ switch (op) {
1840
+ case this.parser.tokenEqual:
1841
+ {
1842
+ var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '') : criteria;
1843
+ for (var i = 0; i < criteriaRange.length; i++) {
1844
+ var sumVal = this.getValueFromRange(sumRange, i);
1845
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join('')).toLowerCase();
1846
+ var val = this.parseFloat(value);
1847
+ if (value === criteria && val === checkCriteria) {
1848
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1849
+ var val1 = this.parseFloat(value1);
1850
+ if (!this.isNaN(val1)) {
1851
+ sum = sum + val1;
1852
+ count = count + 1;
1853
+ }
1854
+ }
1855
+ else if (value === criteria) {
1856
+ if (!this.isNaN(sumVal)) {
1857
+ sum = sum + sumVal;
1858
+ count = count + 1;
1859
+ }
1860
+ }
1861
+ else if (isAsterisk && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
1862
+ var asteriskIndex = criteria.indexOf('*');
1863
+ if (criteria[0] === '*' && criteriaValue.length <= value.length && criteriaValue === value.slice(value.length - criteriaValue.length, value.length)) {
1864
+ if (!this.isNaN(sumVal)) {
1865
+ sum = sum + sumVal;
1866
+ count = count + 1;
1867
+ }
1868
+ }
1869
+ else if (criteria[criteria.length - 1] === '*' && criteriaValue.length <= value.length && criteriaValue === value.slice(0, criteriaValue.length)) {
1870
+ if (!this.isNaN(sumVal)) {
1871
+ sum = sum + sumVal;
1872
+ count = count + 1;
1873
+ }
1874
+ }
1875
+ else if (asteriskIndex > -1 && value.startsWith(criteria.substr(0, asteriskIndex))
1876
+ && value.endsWith(criteria.substr(asteriskIndex + 1))) {
1877
+ if (!this.isNaN(sumVal)) {
1878
+ sum = sum + sumVal;
1879
+ count = count + 1;
1880
+ }
1881
+ }
1882
+ }
1883
+ else if (isAsterisk && !criteriaValue && value && this.isNaN(this.parseFloat(value))) {
1884
+ if (!this.isNaN(sumVal)) {
1885
+ sum = sum + sumVal;
1886
+ count = count + 1;
1887
+ }
1888
+ }
1889
+ else if (isQuestionMark && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
1890
+ var checkRegex = RegExp(criteriaValue.replace(/\?/g, '[\\s\\S]'));
1891
+ if (value.length === criteria.length && value.match(checkRegex)) {
1892
+ if (!this.isNaN(sumVal)) {
1893
+ sum = sum + sumVal;
1894
+ count = count + 1;
1895
+ }
1896
+ }
1897
+ }
1898
+ }
1899
+ }
1900
+ break;
1901
+ case this.parser.tokenLess:
1902
+ {
1903
+ for (var i = 0; i < criteriaRange.length; i++) {
1904
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
1905
+ var val = this.parseFloat(value);
1906
+ if (val < checkCriteria) {
1907
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1908
+ var val1 = this.parseFloat(value1);
1909
+ if (!this.isNaN(val1)) {
1910
+ sum = sum + val1;
1911
+ count = count + 1;
1912
+ }
1913
+ }
1914
+ }
1915
+ }
1916
+ break;
1917
+ case this.parser.tokenGreater:
1918
+ {
1919
+ for (var i = 0; i < criteriaRange.length; i++) {
1920
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
1921
+ var val = this.parseFloat(value);
1922
+ if (val > checkCriteria) {
1923
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1924
+ var val1 = this.parseFloat(value1);
1925
+ if (!this.isNaN(val1)) {
1926
+ sum = sum + val1;
1927
+ count = count + 1;
1928
+ }
1929
+ }
1930
+ }
1931
+ }
1932
+ break;
1933
+ case this.parser.tokenLessEq:
1934
+ {
1935
+ for (var i = 0; i < criteriaRange.length; i++) {
1936
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
1937
+ var val = this.parseFloat(value);
1938
+ if (val <= checkCriteria) {
1939
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1940
+ var val1 = this.parseFloat(value1);
1941
+ if (!this.isNaN(val1)) {
1942
+ sum = sum + val1;
1943
+ count = count + 1;
1944
+ }
1945
+ }
1946
+ }
1947
+ }
1948
+ break;
1949
+ case this.parser.tokenGreaterEq:
1950
+ {
1951
+ for (var i = 0; i < criteriaRange.length; i++) {
1952
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join(''));
1953
+ var val = this.parseFloat(value);
1954
+ if (val >= checkCriteria) {
1955
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1956
+ var val1 = this.parseFloat(value1);
1957
+ if (!this.isNaN(val1)) {
1958
+ sum = sum + val1;
1959
+ count = count + 1;
1960
+ }
1961
+ }
1962
+ }
1963
+ }
1964
+ break;
1965
+ case this.parser.tokenNotEqual:
1966
+ {
1967
+ var criteriaValue = isAsterisk ? criteria.replace(/\*/g, '') : criteria;
1968
+ for (var i = 0; i < criteriaRange.length; i++) {
1969
+ var sumVal = this.getValueFromRange(sumRange, i);
1970
+ var value = this.getValueFromArg(criteriaRange[i].split(this.tic).join('')).toLowerCase();
1971
+ var val = this.parseFloat(value);
1972
+ if (value !== criteria && val !== checkCriteria && !isAsterisk && !isQuestionMark) {
1973
+ var value1 = this.getValueFromArg(sumRange[i].split(this.tic).join(''));
1974
+ var val1 = this.parseFloat(value1);
1975
+ if (!this.isNaN(val1)) {
1976
+ sum = sum + val1;
1977
+ count = count + 1;
1978
+ }
1979
+ }
1980
+ else if (isAsterisk && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
1981
+ var asteriskIndex = criteria.indexOf('*');
1982
+ if (criteria[0] === '*' && criteriaValue.length <= value.length && criteriaValue !== value.slice(value.length - criteriaValue.length, value.length)) {
1983
+ if (!this.isNaN(sumVal)) {
1984
+ sum = sum + sumVal;
1985
+ count = count + 1;
1986
+ }
1987
+ }
1988
+ else if (criteria[criteria.length - 1] === '*' && criteriaValue.length <= value.length && criteriaValue !== value.slice(0, criteriaValue.length)) {
1989
+ if (!this.isNaN(sumVal)) {
1990
+ sum = sum + sumVal;
1991
+ count = count + 1;
1992
+ }
1993
+ }
1994
+ else if (asteriskIndex > -1 && !value.startsWith(criteria.substr(0, asteriskIndex))
1995
+ || !value.endsWith(criteria.substr(asteriskIndex + 1))) {
1996
+ if (!this.isNaN(sumVal)) {
1997
+ sum = sum + sumVal;
1998
+ count = count + 1;
1999
+ }
2000
+ }
2001
+ }
2002
+ else if (isAsterisk && !criteriaValue && !this.isNaN(this.parseFloat(value))) {
2003
+ if (!this.isNaN(sumVal)) {
2004
+ sum = sum + sumVal;
2005
+ count = count + 1;
2006
+ }
2007
+ }
2008
+ else if (isQuestionMark && criteriaValue && value && this.isNaN(this.parseFloat(value))) {
2009
+ var checkRegex = RegExp(criteriaValue.replace(/\?/g, '[\\s\\S]'));
2010
+ if (value.length !== criteria.length || !value.match(checkRegex)) {
2011
+ if (!this.isNaN(sumVal)) {
2012
+ sum = sum + sumVal;
2013
+ count = count + 1;
2014
+ }
2015
+ }
2016
+ }
2017
+ }
2018
+ }
2019
+ break;
2020
+ }
2021
+ return [sum, count];
2022
+ };
2023
+ Calculate.prototype.getValueFromRange = function (sumRange, index) {
2024
+ var sumRangeVal = sumRange[index];
2025
+ sumRangeVal = this.getValueFromArg(sumRangeVal);
2026
+ return this.parseFloat(sumRangeVal.toString());
2027
+ };
2028
+ /**
2029
+ * Evaluates AND / OR / NOT over argument tokens.
2030
+ *
2031
+ * @param {string[]} args - Logical argument tokens.
2032
+ * @param {string} op - Operation name (`"and"`, `"or"`, or `"not"`).
2033
+ * @returns {string} - `"TRUE"`, `"FALSE"`, or an error token.
2034
+ * @hidden
2035
+ */
2036
+ Calculate.prototype.computeAndOrNot = function (args, op) {
2037
+ var _this = this;
2038
+ var isAnd = op === 'and';
2039
+ var isOr = op === 'or';
2040
+ var isNot = op === 'not';
2041
+ var result = (isAnd || isNot) ? true : false;
2042
+ var value;
2043
+ var parseVal;
2044
+ var resultant = [];
2045
+ var ranges = args;
2046
+ for (var i = 0; i < ranges.length; i++) {
2047
+ if (ranges[i] === (this.tic)) {
2048
+ return this.getErrorStrings()[CommonErrors.Value];
2049
+ }
2050
+ ranges[i] = ranges[i].startsWith('n') ? ranges[i].slice(1) : ranges[i];
2051
+ if (this.isCellReference(ranges[i])) {
2052
+ var cells = this.getCellCollection(ranges[i]);
2053
+ for (var j = 0; j < cells.length; j++) {
2054
+ if (this.getErrorStrings().indexOf(cells[j]) > -1) {
2055
+ return cells[j];
2056
+ }
2057
+ else if (cells[j][0] === this.tic) {
2058
+ return this.getErrorStrings()[CommonErrors.Name];
2059
+ }
2060
+ value = this.getValueFromArg(cells[j]);
2061
+ if (this.getErrorStrings().indexOf(value) > -1) {
2062
+ return value;
2063
+ }
2064
+ parseVal = this.parseFloat(value);
2065
+ if (value === this.falseValue || (value !== '' && parseVal === 0) || (isNot && value === '')) {
2066
+ resultant.push(this.falseValue);
2067
+ }
2068
+ else if (value === this.trueValue || !isNaN(parseVal) && value !== '') {
2069
+ resultant.push(this.trueValue);
2070
+ }
2071
+ else if (value === '' || isNaN(parseVal)) {
2072
+ resultant.push(this.getErrorStrings()[CommonErrors.Value]);
2073
+ }
2074
+ }
2075
+ }
2076
+ else {
2077
+ value = this.getValueFromArg(ranges[i]).toUpperCase();
2078
+ if (this.getErrorStrings().indexOf(value) > -1) {
2079
+ return value;
2080
+ }
2081
+ parseVal = this.parseFloat(value);
2082
+ value = value.split(this.tic).join('');
2083
+ if (value === this.falseValue || ranges[i] === '' || (value !== '' && parseVal === 0)) {
2084
+ resultant.push(this.falseValue);
2085
+ }
2086
+ else if (value === this.trueValue || !isNaN(parseVal) && value !== '') {
2087
+ resultant.push(this.trueValue);
2088
+ }
2089
+ else if (value === '' || isNaN(parseVal)) {
2090
+ resultant.push(this.getErrorStrings()[CommonErrors.Value]);
2091
+ }
2092
+ }
2093
+ }
2094
+ var containsOnlyValueError = resultant.every(function (item) { return item === _this.getErrorStrings()[CommonErrors.Value]; });
2095
+ if (containsOnlyValueError) {
2096
+ return this.getErrorStrings()[CommonErrors.Value];
2097
+ }
2098
+ for (var j = 0; j < resultant.length; j++) {
2099
+ if ((isAnd || isNot) && resultant[j] === this.falseValue) {
2100
+ result = false;
2101
+ break;
2102
+ }
2103
+ if (isOr && resultant[j] === this.trueValue) {
2104
+ result = true;
2105
+ break;
2106
+ }
2107
+ }
2108
+ result = isNot ? !result : result;
2109
+ return result ? this.trueValue : this.falseValue;
2110
+ };
2111
+ /**
2112
+ * @hidden
2113
+ * @param {string} text - specify the text
2114
+ * @returns {string} - to strip out the tic from the formula arguments.
2115
+ */
2116
+ // To strip out the tic from the formula arguments.
2117
+ /**
2118
+ * Strips surrounding formula string quotes (`"...`) when present.
2119
+ *
2120
+ * @param {string} text - Possibly quoted text.
2121
+ * @returns {string} - Unquoted text.
2122
+ * @hidden
2123
+ */
2124
+ Calculate.prototype.removeTics = function (text) {
2125
+ if (text.length > 1 && text[0] === this.tic[0] && text[text.length - 1] === this.tic[0]) {
2126
+ text = this.substring(text, 1, text.length - 2);
2127
+ }
2128
+ return text;
2129
+ };
2130
+ /**
2131
+ * Returns the top-left cell address from a range string.
2132
+ *
2133
+ * @param {string} range - Range such as `A1:B2`.
2134
+ * @returns {string | number} - Starting cell address.
2135
+ * @hidden
2136
+ */
2137
+ Calculate.prototype.getCellFrom = function (range) {
2138
+ var cellRange = '';
2139
+ var cells = range.indexOf(':') > -1 ? range.split(':') : [range];
2140
+ //this.getCellsFromArgs(range);
2141
+ var last = cells.length - 1;
2142
+ var r1 = this.rowIndex(cells[0]);
2143
+ var x;
2144
+ if (r1 === this.rowIndex(cells[last])) {
2145
+ var c1 = this.colIndex(cells[0]);
2146
+ var c2 = this.colIndex(cells[last]);
2147
+ var c = this.colIndex(this.cell);
2148
+ if (c >= c1 && c <= c2) {
2149
+ cellRange = getAlphalabel(c).toString() + r1.toString();
2150
+ }
2151
+ }
2152
+ else if (this.colIndex(cells[0]) === this.colIndex(cells[last])) {
2153
+ x = this.colIndex(cells[0]);
2154
+ var r2 = this.rowIndex(cells[last]);
2155
+ var r = this.rowIndex(this.cell);
2156
+ if (r >= r1 && r <= r2) {
2157
+ cellRange = getAlphalabel(x).toString() + r.toString();
2158
+ }
2159
+ }
2160
+ return cellRange;
2161
+ };
2162
+ Calculate.prototype.computeValue = function (pFormula, refresh, isIfError) {
2163
+ try {
2164
+ var stack = [];
2165
+ var i = 0;
2166
+ var sheet = '';
2167
+ stack.length = 0;
2168
+ var emptyStack = [];
2169
+ var decimalSep = this.getParseDecimalSeparator();
2170
+ while (i < pFormula.length) {
2171
+ var uFound = pFormula[i] === 'u'; // for 3*-2
2172
+ if (uFound) {
2173
+ i = i + 1; // for the cell reference cases, like A1*-A2.
2174
+ }
2175
+ if (pFormula[i] === this.arithMarker) {
2176
+ i = i + 1;
2177
+ continue;
2178
+ }
2179
+ else if (this.isDigit(pFormula[i])) {
2180
+ var s = '';
2181
+ while (i < pFormula.length && (this.isDigit(pFormula[i]) ||
2182
+ pFormula[i] === decimalSep)) {
2183
+ s += pFormula[i] === decimalSep ? '.' : pFormula[i];
2184
+ i = i + 1;
2185
+ }
2186
+ stack.push(s);
2187
+ if (!pFormula[i]) {
2188
+ return stack.toString();
2189
+ }
2190
+ }
2191
+ if (pFormula[i] === this.sheetToken) {
2192
+ sheet = pFormula[i];
2193
+ i = i + 1;
2194
+ while (i < pFormula.length && pFormula[i] !== this.sheetToken) {
2195
+ sheet = sheet + pFormula[i];
2196
+ i = i + 1;
2197
+ }
2198
+ if (i < pFormula.length) {
2199
+ sheet = sheet + pFormula[i];
2200
+ i = i + 1;
2201
+ }
2202
+ }
2203
+ else if (this.isUpperChar(pFormula[i])) {
2204
+ var s = '';
2205
+ var textName = '';
2206
+ while (i < pFormula.length && this.isUpperChar(pFormula[i])) {
2207
+ var char = pFormula[i];
2208
+ s = s + char;
2209
+ i = i + 1;
2210
+ }
2211
+ while (i < pFormula.length && this.isDigit(pFormula[i])) {
2212
+ var digit = pFormula[i];
2213
+ s = s + digit;
2214
+ i = i + 1;
2215
+ }
2216
+ if (i < pFormula.length && pFormula[i] === ':') {
2217
+ s = s + pFormula[i];
2218
+ i = i + 1;
2219
+ if (i < pFormula.length && pFormula[i] === this.sheetToken) {
2220
+ s = s + pFormula[i];
2221
+ i = i + 1;
2222
+ while (i < pFormula.length && pFormula[i] !== this.sheetToken) {
2223
+ s = s + pFormula[i];
2224
+ i = i + 1;
2225
+ }
2226
+ }
2227
+ while (i < pFormula.length && this.isUpperChar(pFormula[i])) {
2228
+ s = s + pFormula[i];
2229
+ i = i + 1;
2230
+ }
2231
+ while (i < pFormula.length && this.isDigit(pFormula[i])) {
2232
+ s = s + pFormula[i];
2233
+ i = i + 1;
2234
+ }
2235
+ s = sheet + this.getCellFrom(s);
2236
+ }
2237
+ else {
2238
+ s = sheet + s;
2239
+ }
2240
+ var parentCellValue = this.getParentObjectCellValue(s, refresh);
2241
+ textName = isNullOrUndefined(parentCellValue) ? '' : parentCellValue.toString();
2242
+ sheet = '';
2243
+ if (typeof textName === 'string' && this.getErrorStrings().indexOf(textName) > -1) {
2244
+ return textName;
2245
+ }
2246
+ if (uFound) {
2247
+ if (!this.isNaN(this.parseFloat(textName))) {
2248
+ textName = (-(this.parseFloat(textName))).toString();
2249
+ }
2250
+ else {
2251
+ textName = '-' + textName;
2252
+ }
2253
+ }
2254
+ stack.push(textName);
2255
+ if (textName === '') {
2256
+ emptyStack[stack.length - 1] = '0';
2257
+ }
2258
+ }
2259
+ else if (pFormula[i] === 'q') {
2260
+ var leftIdx = pFormula.substring(i + 1).indexOf(this.leftBracket);
2261
+ var j = pFormula.substring(i + leftIdx + 1).indexOf(this.rightBracket);
2262
+ pFormula = this.substring(pFormula, i + leftIdx + 2, j - 1);
2263
+ }
2264
+ else if (pFormula[i] === this.tic[0]) {
2265
+ var s = pFormula[i].toString();
2266
+ i = i + 1;
2267
+ var isNestedFormulaVal = pFormula[i - 2] === 'n' && pFormula[i] === this.tic[0];
2268
+ while (i < pFormula.length && pFormula[i] !== this.tic[0]) {
2269
+ s = s + pFormula[i];
2270
+ i = i + 1;
2271
+ }
2272
+ var textName = s.split(this.tic).join('');
2273
+ if (textName === this.trueValue || textName === this.falseValue ||
2274
+ (!this.isNaN(this.parseFloat(textName)) && textName !== '')) {
2275
+ stack.push(this.tic + textName + this.tic);
2276
+ }
2277
+ else {
2278
+ stack.push(textName);
2279
+ if (textName === '' && isNestedFormulaVal) {
2280
+ emptyStack[stack.length - 1] = '0';
2281
+ }
2282
+ }
2283
+ i = i + 1;
2284
+ }
2285
+ else if (pFormula[i] === '%' && stack.length > 0) {
2286
+ var stackValue = stack[0];
2287
+ var value = this.parseFloat(stackValue);
2288
+ if (!this.isNaN(value)) {
2289
+ stack.pop();
2290
+ stack.push((value / 100).toString());
2291
+ }
2292
+ i = i + 1;
2293
+ }
2294
+ else if ((pFormula.substring(i)).indexOf(this.trueValue) === 0) {
2295
+ stack.push(this.trueValue);
2296
+ i += this.trueValue.length;
2297
+ }
2298
+ else if (pFormula.substring(i).indexOf(this.falseValue) === 0) {
2299
+ stack.push(this.falseValue);
2300
+ i += this.falseValue.length;
2301
+ }
2302
+ else if (pFormula[i] === this.tic[0] || pFormula[i] === '|') {
2303
+ var s = pFormula[i].toString();
2304
+ i++;
2305
+ while (i < pFormula.length && pFormula[i] !== this.tic[0]) {
2306
+ s = s + pFormula[i];
2307
+ i = i + 1;
2308
+ }
2309
+ stack.push(s + this.tic);
2310
+ i += 1;
2311
+ }
2312
+ else {
2313
+ if (pFormula[i] === ' ' && i < pFormula.length - 1) {
2314
+ i += 1;
2315
+ continue;
2316
+ }
2317
+ switch (pFormula[i]) {
2318
+ case '#':
2319
+ {
2320
+ var errIndex = 0;
2321
+ if (this.getErrorStrings().indexOf(pFormula.substring(i)) > -1) {
2322
+ if (pFormula.indexOf('!') === -1 || pFormula.substring(i).indexOf('!') === -1) {
2323
+ errIndex = pFormula.indexOf('#N/A') > -1 ? (pFormula.indexOf('#N/A') + 4 + i) : pFormula.indexOf('?') + 1 + i;
2324
+ }
2325
+ else {
2326
+ errIndex = pFormula.indexOf('!') + 1 + i;
2327
+ }
2328
+ stack.push(this.substring(pFormula, i, errIndex - i));
2329
+ }
2330
+ else {
2331
+ errIndex = i + 1;
2332
+ stack.push(this.substring(pFormula, i, errIndex - i));
2333
+ }
2334
+ i = errIndex;
2335
+ }
2336
+ break;
2337
+ case 'n':
2338
+ {
2339
+ i = i + 1;
2340
+ var s = '';
2341
+ if (pFormula[i] === 'n') {
2342
+ continue;
2343
+ }
2344
+ if (pFormula.substring(i).indexOf('Infinity') === 0) {
2345
+ s = 'Infinity';
2346
+ i += s.length;
2347
+ }
2348
+ else {
2349
+ if (pFormula[i] === 'u' || uFound || pFormula[i] === '-') {
2350
+ s = '-';
2351
+ if (!uFound) {
2352
+ i = i + 1;
2353
+ }
2354
+ else {
2355
+ uFound = false;
2356
+ }
2357
+ }
2358
+ while (i < pFormula.length && (this.isDigit(pFormula[i]) ||
2359
+ (pFormula[i] === decimalSep || pFormula[i] === '.'))) {
2360
+ s += pFormula[i] === decimalSep ? '.' : pFormula[i];
2361
+ i = i + 1;
2362
+ }
2363
+ if (i < pFormula.length && pFormula[i] === '%') {
2364
+ i = i + 1;
2365
+ if (s === '') {
2366
+ if (stack.length > 0) {
2367
+ var stackValue = stack[0];
2368
+ var value = this.parseFloat(stackValue);
2369
+ if (!this.isNaN(value)) {
2370
+ stack.pop();
2371
+ stack.push((value / 100).toString());
2372
+ }
2373
+ }
2374
+ }
2375
+ else {
2376
+ s = (this.parseFloat(s) / 100).toString();
2377
+ }
2378
+ }
2379
+ }
2380
+ if (s) {
2381
+ stack.push(s);
2382
+ }
2383
+ }
2384
+ break;
2385
+ case this.parser.tokenAdd:
2386
+ {
2387
+ this.getValArithmetic(stack, 'add', isIfError);
2388
+ i = i + 1;
2389
+ }
2390
+ break;
2391
+ case this.parser.tokenSubtract:
2392
+ {
2393
+ this.getValArithmetic(stack, 'sub', isIfError);
2394
+ i = i + 1;
2395
+ }
2396
+ break;
2397
+ case this.parser.tokenMultiply:
2398
+ {
2399
+ this.getValArithmetic(stack, 'mul', isIfError);
2400
+ i = i + 1;
2401
+ }
2402
+ break;
2403
+ case this.parser.tokenDivide:
2404
+ {
2405
+ this.getValArithmetic(stack, 'div', isIfError);
2406
+ i = i + 1;
2407
+ }
2408
+ break;
2409
+ case this.parser.tokenLess:
2410
+ {
2411
+ this.processLogical(stack, 'less');
2412
+ i = i + 1;
2413
+ }
2414
+ break;
2415
+ case this.parser.tokenGreater:
2416
+ {
2417
+ this.processLogical(stack, 'greater');
2418
+ i = i + 1;
2419
+ }
2420
+ break;
2421
+ case this.parser.tokenGreaterEq:
2422
+ {
2423
+ this.processLogical(stack, 'greaterEq');
2424
+ i = i + 1;
2425
+ }
2426
+ break;
2427
+ case this.parser.tokenLessEq:
2428
+ {
2429
+ this.processLogical(stack, 'lessEq');
2430
+ i = i + 1;
2431
+ }
2432
+ break;
2433
+ case this.parser.tokenNotEqual:
2434
+ {
2435
+ this.processLogical(stack, 'notEq', emptyStack);
2436
+ emptyStack.length = 0;
2437
+ i = i + 1;
2438
+ }
2439
+ break;
2440
+ case this.parser.tokenOr:
2441
+ {
2442
+ this.processLogical(stack, 'or');
2443
+ i = i + 1;
2444
+ }
2445
+ break;
2446
+ case this.parser.tokenAnd:
2447
+ {
2448
+ this.processLogical(stack, 'and');
2449
+ i = i + 1;
2450
+ }
2451
+ break;
2452
+ case this.parser.tokenEqual:
2453
+ {
2454
+ this.processLogical(stack, 'equal', emptyStack);
2455
+ emptyStack.length = 0;
2456
+ i = i + 1;
2457
+ }
2458
+ break;
2459
+ default: {
2460
+ return this.getErrorStrings()[CommonErrors.Value];
2461
+ }
2462
+ }
2463
+ }
2464
+ }
2465
+ if (stack.length === 0) {
2466
+ return '';
2467
+ }
2468
+ else {
2469
+ var s = '';
2470
+ var countValue = stack.length;
2471
+ while (countValue > 0) {
2472
+ var sCheck = stack.pop();
2473
+ if (this.getErrorStrings().indexOf(sCheck) > -1) {
2474
+ return sCheck;
2475
+ }
2476
+ else {
2477
+ s = sCheck + s;
2478
+ if (s === '' && this.isCellReference(pFormula) &&
2479
+ this.getTreatEmptyStringAsZero()) {
2480
+ return '0';
2481
+ }
2482
+ countValue--;
2483
+ }
2484
+ }
2485
+ return s;
2486
+ }
2487
+ }
2488
+ catch (ex) {
2489
+ if (this.getErrorStrings().indexOf(ex) > -1 || this.formulaErrorStrings.indexOf(ex) > -1) {
2490
+ throw ex;
2491
+ }
2492
+ throw new FormulaError(this.formulaErrorStrings[FormulasErrorsStrings.InvalidExpression]);
2493
+ }
2494
+ };
2495
+ Calculate.prototype.getValArithmetic = function (stack, operator, isIfError) {
2496
+ var isErrorString = false;
2497
+ var num1 = stack.pop();
2498
+ var decimalCount1 = num1.indexOf('.') !== -1 ? num1.split('.')[1].length : 0;
2499
+ var factor1 = Math.pow(10, decimalCount1);
2500
+ var num2 = stack.pop();
2501
+ var decimalCount2 = num2.indexOf('.') !== -1 ? num2.split('.')[1].length : 0;
2502
+ var factor2 = Math.pow(10, decimalCount2);
2503
+ var bigFactor = factor1 >= factor2 ? factor1 : factor2;
2504
+ var factors = factor1 * factor2;
2505
+ num1 = num1 === this.trueValue ? '1' : (num1 === this.falseValue ? '0' : num1);
2506
+ num1 = num1 === '' ? '0' : (this.getErrorStrings().indexOf(num1.toString()) < 0 ? this.parseFloat(num1 + '').toString() : num1);
2507
+ var num = Number(num1);
2508
+ if (isNaN(num) && !isIfError) {
2509
+ isErrorString = true;
2510
+ if (num1 === this.getErrorStrings()[CommonErrors.DivZero]) {
2511
+ stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
2512
+ }
2513
+ else {
2514
+ stack.push(this.getErrorStrings()[CommonErrors.Value]);
2515
+ }
2516
+ }
2517
+ num2 = num2 === this.trueValue ? '1' : (num2 === this.falseValue ? '0' : num2);
2518
+ num2 = num2 === '' ? '0' : (this.getErrorStrings().indexOf(num2.toString()) < 0 ? this.parseFloat(num2 + '').toString() : num2);
2519
+ num = Number(num2);
2520
+ if (isNaN(num) && !isIfError) {
2521
+ isErrorString = true;
2522
+ if (num2 === this.getErrorStrings()[CommonErrors.DivZero]) {
2523
+ stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
2524
+ }
2525
+ else {
2526
+ stack.push(this.getErrorStrings()[CommonErrors.Value]);
2527
+ }
2528
+ }
2529
+ if (operator === 'add' && !isErrorString) {
2530
+ stack.push(((((Number(num2) * bigFactor) + (Number(num1) * bigFactor)) / bigFactor)).toString());
2531
+ }
2532
+ if (operator === 'sub' && !isErrorString) {
2533
+ stack.push(((((Number(num2) * bigFactor) - (Number(num1) * bigFactor)) / bigFactor)).toString());
2534
+ }
2535
+ if (operator === 'mul' && !isErrorString) {
2536
+ stack.push(((((Number(num2) * factor2) * (Number(num1) * factor1)) / factors)).toString());
2537
+ }
2538
+ if (operator === 'div' && !isErrorString) {
2539
+ if (this.isNaN(this.parseFloat(num1)) || this.isNaN(this.parseFloat(num2))) {
2540
+ stack.push(this.getErrorStrings()[CommonErrors.Value]);
2541
+ }
2542
+ else if (this.parseFloat(num1) === 0) {
2543
+ stack.push(this.getErrorStrings()[CommonErrors.DivZero]);
2544
+ }
2545
+ else {
2546
+ stack.push(((Number(num2) * factors) / (Number(num1) * factors)).toString());
2547
+ }
2548
+ }
2549
+ };
2550
+ /**
2551
+ * Applies a comparison operator to values on the evaluation stack.
2552
+ *
2553
+ * @param {string | number | Object} stack - Value stack.
2554
+ * @param {string | number | Object} operator - Comparison / logical operator token.
2555
+ * @param {string | number | Object} emptyStack - Optional alternate stack for empty handling.
2556
+ * @returns {string} - `"TRUE"`, `"FALSE"`, or an error token.
2557
+ * @hidden
2558
+ */
2559
+ Calculate.prototype.processLogical = function (stack, operator, emptyStack) {
2560
+ var val1;
2561
+ var val2;
2562
+ var value1;
2563
+ var value2;
2564
+ var isOnlyAsterisk;
2565
+ var result;
2566
+ var isErrorString = false;
2567
+ if (operator !== 'and' && operator !== 'equal' && operator !== 'notEq') {
2568
+ val1 = stack.pop();
2569
+ val2 = stack.pop();
2570
+ if (this.getErrorStrings().indexOf(val1) > -1) {
2571
+ result = val1;
2572
+ isErrorString = true;
2573
+ }
2574
+ else if (this.getErrorStrings().indexOf(val2) > -1) {
2575
+ result = val2;
2576
+ isErrorString = true;
2577
+ }
2578
+ if (this.isNaN(this.parseFloat(val1)) && this.isNaN(this.parseFloat(val2))) {
2579
+ val1 = val1.toString().toLowerCase();
2580
+ val2 = val2.toString().toLowerCase();
2581
+ }
2582
+ if (!isNullOrUndefined(val1)) {
2583
+ value1 = val1.indexOf(this.tic) > -1 ? val1 : this.parseFloat(val1);
2584
+ }
2585
+ if (!isNullOrUndefined(val2)) {
2586
+ value2 = val2.indexOf(this.tic) > -1 ? val2 : this.parseFloat(val2);
2587
+ }
2588
+ if (val1 === '*' && this.isNaN(this.parseFloat(val2)) && val2 !== '') {
2589
+ isOnlyAsterisk = true;
2590
+ }
2591
+ }
2592
+ if (operator === 'less' && !isErrorString) {
2593
+ if (!this.isNaN(value1) && !this.isNaN(value2)) {
2594
+ result = (value2 < value1) ? this.trueValue : this.falseValue;
2595
+ }
2596
+ else {
2597
+ result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) < 0) ?
2598
+ this.trueValue : this.falseValue;
2599
+ }
2600
+ }
2601
+ if (operator === 'greater' && !isErrorString) {
2602
+ if (!this.isNaN(value1) && !this.isNaN(value2)) {
2603
+ result = (value2 > value1) ? this.trueValue : this.falseValue;
2604
+ }
2605
+ else {
2606
+ result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) > 0) ?
2607
+ this.trueValue : this.falseValue;
2608
+ }
2609
+ }
2610
+ if (operator === 'lessEq' && !isErrorString) {
2611
+ if (!this.isNaN(value1) && !this.isNaN(value2)) {
2612
+ result = (value2 <= value1) ? this.trueValue : this.falseValue;
2613
+ }
2614
+ else {
2615
+ result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) <= 0) ?
2616
+ this.trueValue : this.falseValue;
2617
+ }
2618
+ }
2619
+ if (operator === 'greaterEq' && !isErrorString) {
2620
+ if (!this.isNaN(value1) && !this.isNaN(value2)) {
2621
+ result = (value2 >= value1) ? this.trueValue : this.falseValue;
2622
+ }
2623
+ else {
2624
+ result = (val2.toUpperCase().split(this.tic).join('').localeCompare(val1.toUpperCase().split(this.tic).join('')) >= 0) ?
2625
+ this.trueValue : this.falseValue;
2626
+ }
2627
+ }
2628
+ if (operator === 'and' && !isErrorString) {
2629
+ val1 = stack.pop().toString();
2630
+ val2 = '';
2631
+ if (stack.length > 0) {
2632
+ val2 = stack.pop().toString();
2633
+ }
2634
+ if (this.getErrorStrings().indexOf(val1) > -1) {
2635
+ result = val1;
2636
+ }
2637
+ else if (this.getErrorStrings().indexOf(val2) > -1) {
2638
+ result = val2;
2639
+ }
2640
+ else {
2641
+ result = '' + val2 + val1 + '';
2642
+ result = result.split(this.tic).join('');
2643
+ }
2644
+ }
2645
+ if ((operator === 'equal' || operator === 'notEq') && !isErrorString) {
2646
+ var emptyValue1 = void 0;
2647
+ var emptyValue2 = void 0;
2648
+ if (emptyStack) {
2649
+ emptyValue1 = emptyStack[stack.length - 1];
2650
+ val1 = stack.pop();
2651
+ emptyValue2 = emptyStack[stack.length - 1];
2652
+ val2 = stack.pop();
2653
+ }
2654
+ else {
2655
+ val1 = stack.pop();
2656
+ val2 = stack.pop();
2657
+ }
2658
+ if (this.getErrorStrings().indexOf(val1) > -1) {
2659
+ result = val1;
2660
+ }
2661
+ else if (this.getErrorStrings().indexOf(val2) > -1) {
2662
+ result = val2;
2663
+ }
2664
+ else {
2665
+ val1 = (val1 === 'TRUE') ? '1' : (val1 === 'FALSE') ? '0' : val1;
2666
+ val2 = (val2 === 'TRUE') ? '1' : (val2 === 'FALSE') ? '0' : val2;
2667
+ if (this.isNaN(this.parseFloat(val1)) && this.isNaN(this.parseFloat(val2))) {
2668
+ val1 = val1.toString().toLowerCase();
2669
+ val2 = val2.toString().toLowerCase();
2670
+ }
2671
+ if (val1 === '*' && this.isNaN(this.parseFloat(val2)) && val2 !== '') {
2672
+ isOnlyAsterisk = true;
2673
+ }
2674
+ if (operator === 'equal') {
2675
+ result = val1 === val2 || (emptyValue1 !== undefined && emptyValue1 === val2) ||
2676
+ (emptyValue2 !== undefined && emptyValue2 === val1) || isOnlyAsterisk ? this.trueValue : this.falseValue;
2677
+ }
2678
+ else {
2679
+ if (isOnlyAsterisk) {
2680
+ result = this.falseValue;
2681
+ }
2682
+ else {
2683
+ result = val2 !== val1 && (!emptyValue1 || emptyValue1 !== val2) &&
2684
+ (!emptyValue2 || emptyValue2 !== val1) ? this.trueValue : this.falseValue;
2685
+ }
2686
+ }
2687
+ }
2688
+ }
2689
+ if (operator === 'or' && !isErrorString) {
2690
+ result = Math.pow(this.parseFloat(value2), this.parseFloat(value1)).toString();
2691
+ result = this.isNaN(this.parseFloat(result)) ? this.getErrorStrings()[CommonErrors.Value] : result;
2692
+ }
2693
+ stack.push(result);
2694
+ return result;
2695
+ };
2696
+ /**
2697
+ * Stores and expands cells for multi-criteria IFS formulas.
2698
+ *
2699
+ * @param {string} sCell - Stored cell info payload.
2700
+ * @returns {string | number} - Expanded stored cell list.
2701
+ * @hidden
2702
+ */
2703
+ Calculate.prototype.computeStoreCells = function (sCell) {
2704
+ var cellValue = sCell.cellValue;
2705
+ var cellRanges = sCell.cellRange;
2706
+ var criterias = sCell.criteria;
2707
+ var argArr = sCell.argArray;
2708
+ var isCriteria = sCell.isCriteria;
2709
+ var storeCell = sCell.storedCells;
2710
+ var isCountIfs = sCell.isCountIfS === this.trueValue;
2711
+ var i = sCell.countVal || 0;
2712
+ var rangeLength = isCriteria === this.trueValue ? storeCell : cellValue;
2713
+ var tempStoredCell = [];
2714
+ var criteria;
2715
+ for (var j = 0; j < rangeLength.length; j++) {
2716
+ var stack = [];
2717
+ var cellVal = this.getValueFromArg(cellValue[j]);
2718
+ var arrValue = argArr[isCountIfs ? (1 + (i * 2)) : (2 + i)];
2719
+ var isStringVal = arrValue.startsWith(this.tic) && arrValue.endsWith(this.tic);
2720
+ criteria = this.getANDComputedValue(arrValue.trim());
2721
+ var isAsterisk = criteria.includes('*');
2722
+ var isAsteriskOnly = criteria === '*' || criteria === '<>*';
2723
+ var criteriaValue = isAsterisk && !isAsteriskOnly ? criteria.replace(/\*/g, '').trim() : criteria;
2724
+ var isCellReferenceValue = false;
2725
+ if (!isStringVal && this.isCellReference(criteriaValue)) {
2726
+ criteriaValue = this.getValueFromArg(criteriaValue);
2727
+ isCellReferenceValue = true;
2728
+ }
2729
+ if (isAsterisk && !isAsteriskOnly) {
2730
+ var asteriskIndex = criteria.indexOf('*');
2731
+ if (criteria[0] === '*') {
2732
+ criteriaValue = '*' + criteriaValue;
2733
+ }
2734
+ if (criteria[criteria.length - 1] === '*') {
2735
+ criteriaValue += '*';
2736
+ }
2737
+ if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
2738
+ criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
2739
+ }
2740
+ }
2741
+ criteria = criteriaValue;
2742
+ var newCell = '';
2743
+ isCriteria = isCountIfs ? this.trueValue : isCriteria;
2744
+ if (isCriteria === this.trueValue) {
2745
+ var cell = '';
2746
+ var count = 0;
2747
+ var newCount = 0;
2748
+ var prevCriteria = void 0;
2749
+ var prevCriteriaIdx = void 0;
2750
+ var prevStoreCellIdx = void 0;
2751
+ var criteriaRangeIndexes = void 0;
2752
+ storeCell[j] = isCountIfs && !i ? cellValue[j] : storeCell[j];
2753
+ cell = storeCell[j];
2754
+ if (i) {
2755
+ prevCriteria = cellRanges[i - 1];
2756
+ prevCriteriaIdx = prevCriteria.indexOf('!') > -1 ? getRangeIndexes(prevCriteria.substring(prevCriteria.lastIndexOf('!') + 1)) : getRangeIndexes(prevCriteria);
2757
+ prevStoreCellIdx = cell.indexOf('!') > -1 ? getCellIndexes(cell.substring(cell.lastIndexOf('!') + 1)) : getCellIndexes(cell);
2758
+ criteriaRangeIndexes = cellRanges[i].indexOf('!') > -1 ?
2759
+ getRangeIndexes(cellRanges[i].substring(cellRanges[i].lastIndexOf('!') + 1)) :
2760
+ getRangeIndexes(cellRanges[i]);
2761
+ }
2762
+ var isCriteriaFromOtherSheet = cell.indexOf('!') > -1;
2763
+ var isSumFromOtherSheet = void 0;
2764
+ var sumRangeSheet = '';
2765
+ var criteriaRangeSheet = '';
2766
+ if (isCriteriaFromOtherSheet) {
2767
+ criteriaRangeSheet = cell.substring(0, cell.lastIndexOf('!') + 1);
2768
+ cell = cell.substring(cell.lastIndexOf('!') + 1);
2769
+ }
2770
+ // convert the new cell ranges for find in range with criteria.
2771
+ while (!this.isDigit(cell[count])) {
2772
+ count = count + 1;
2773
+ }
2774
+ if (this.isCellReference(cellRanges[i]) && cellRanges[i].indexOf(':') > -1) {
2775
+ newCell = isCountIfs && !i ? (rangeLength[j].indexOf('!') > -1 ? rangeLength[j].substring(rangeLength[j].lastIndexOf('!') + 1) : rangeLength[j]) : getCellAddress(criteriaRangeIndexes[0] + (prevStoreCellIdx[0] - prevCriteriaIdx[0]), criteriaRangeIndexes[1] +
2776
+ (prevStoreCellIdx[1] - prevCriteriaIdx[1]));
2777
+ isSumFromOtherSheet = cellRanges[i].indexOf('!') > -1;
2778
+ if (isSumFromOtherSheet) {
2779
+ sumRangeSheet = cellRanges[i].substring(0, cellRanges[i].lastIndexOf('!') + 1);
2780
+ }
2781
+ while (!this.isDigit(newCell[newCount])) {
2782
+ newCount = newCount + 1;
2783
+ }
2784
+ }
2785
+ var cellAlpha = this.substring(cell, count);
2786
+ var newCellAlpha = this.substring(newCell, newCount);
2787
+ var cellNumeric = this.substring(cell, count, cell.length - count);
2788
+ var newCellNumeric = this.substring(newCell, newCount, newCell.length - count);
2789
+ if (isCriteriaFromOtherSheet) {
2790
+ cellAlpha = criteriaRangeSheet + cellAlpha;
2791
+ newCellAlpha = criteriaRangeSheet + newCellAlpha;
2792
+ }
2793
+ if (cellNumeric !== newCellNumeric) {
2794
+ storeCell[j] = this.substring(storeCell[j], isCriteriaFromOtherSheet ? (criteriaRangeSheet.length + count) : count) + newCellNumeric;
2795
+ }
2796
+ newCell = storeCell[j].split(cellAlpha).join(newCellAlpha);
2797
+ if (isSumFromOtherSheet) {
2798
+ if (newCell.indexOf('!') > -1) {
2799
+ newCell = newCell.substring(newCell.lastIndexOf('!') + 1);
2800
+ }
2801
+ newCell = sumRangeSheet + newCell;
2802
+ }
2803
+ else {
2804
+ newCell = newCell.substring(newCell.lastIndexOf('!') + 1);
2805
+ }
2806
+ cellVal = this.getValueFromArg(newCell);
2807
+ criteria = isCountIfs ? criteria : this.getANDComputedValue(criterias[i - 1]);
2808
+ }
2809
+ var op = 'equal';
2810
+ var updatedCriteria = this.getOperatorAndCriteria(criteria, op);
2811
+ op = updatedCriteria.op;
2812
+ criteria = updatedCriteria.criteria;
2813
+ if ((!isStringVal && this.isCellReference(criteria) && (!isCellReferenceValue || (newCell !== '' && !isCountIfs))) || criteria.includes(this.arithMarker)) {
2814
+ criteria = this.getValueFromArg(criteria);
2815
+ }
2816
+ if (criteria.indexOf('*') > -1 || criteria.indexOf('?') > -1) {
2817
+ cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
2818
+ }
2819
+ stack.push(cellVal.toLowerCase());
2820
+ stack.push(criteria.toLowerCase());
2821
+ if (this.processLogical(stack, op) === this.trueValue) {
2822
+ if (isCriteria === this.falseValue) {
2823
+ tempStoredCell.push(cellValue[j]);
2824
+ }
2825
+ else {
2826
+ tempStoredCell.push(newCell);
2827
+ }
2828
+ }
2829
+ }
2830
+ storeCell = tempStoredCell;
2831
+ tempStoredCell = [];
2832
+ return storeCell;
2833
+ };
2834
+ /**
2835
+ * Shared SUMIFS / AVERAGEIFS evaluation entry point.
2836
+ *
2837
+ * @param {string} range - Argument tokens for the IFS aggregate.
2838
+ * @param {boolean} isCountIfs - COUNTIFS marker when applicable.
2839
+ * @param {string} isAvgIfs - AVERAGEIFS marker when applicable.
2840
+ * @returns {string} - Aggregate result or error token.
2841
+ * @hidden
2842
+ */
2843
+ Calculate.prototype.computeIfsFormulas = function (range, isCountIfs, isAvgIfs) {
2844
+ if (isCountIfs === this.trueValue && (isNullOrUndefined(range) || range[0] === '' || range.length < 2 || range.length > 127 ||
2845
+ range.length % 2 !== 0)) {
2846
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
2847
+ }
2848
+ var argArr = range;
2849
+ var cellRanges = [];
2850
+ var criterias = [];
2851
+ var storedCell = [];
2852
+ var storedCellLength = 0;
2853
+ var sum = 0;
2854
+ for (var i = 0; i < argArr.length; i++) {
2855
+ if ((i === 0 || i % 2 === 1) && this.isCellReference(argArr[i])) {
2856
+ cellRanges.push(argArr[i].indexOf(':') > -1 ?
2857
+ argArr[i].trim() : getRangeAddress(getRangeIndexes(argArr[i])));
2858
+ }
2859
+ else {
2860
+ criterias.push(argArr[i].trim());
2861
+ }
2862
+ }
2863
+ var len = [];
2864
+ for (var i = 0; i < cellRanges.length; i++) {
2865
+ len.push(this.getCellCollection(cellRanges[i]).length);
2866
+ }
2867
+ for (var j = 0; j < len.length; j++) {
2868
+ if (len[j] && len[j + 1] && len[j] !== len[j + 1]) {
2869
+ return this.getErrorStrings()[CommonErrors.Value];
2870
+ }
2871
+ }
2872
+ for (var k = 0; k < criterias.length; k++) {
2873
+ if (criterias[k] === '' || (this.isCellReference(criterias[k]) &&
2874
+ this.getValueFromArg(criterias[k]) === '')) {
2875
+ if (isAvgIfs === this.trueValue) {
2876
+ return this.getErrorStrings()[CommonErrors.DivZero];
2877
+ }
2878
+ return 0;
2879
+ }
2880
+ }
2881
+ var cellvalue;
2882
+ var isCriteria;
2883
+ if (isCountIfs === this.falseValue) {
2884
+ isCriteria = this.falseValue;
2885
+ cellvalue = this.getCellCollection(cellRanges[1]);
2886
+ var sCell = {
2887
+ cellValue: cellvalue, cellRange: cellRanges, criteria: criterias,
2888
+ argArray: argArr, isCriteria: isCriteria, storedCells: storedCell, isCountIfS: isCountIfs
2889
+ };
2890
+ storedCell = this.computeStoreCells(sCell);
2891
+ storedCellLength = storedCell.length;
2892
+ if (storedCellLength === 0) {
2893
+ return isAvgIfs === this.trueValue ? this.getErrorStrings()[CommonErrors.DivZero] : 0;
2894
+ }
2895
+ }
2896
+ // Compare criteria and convert the new cell ranges.
2897
+ var startRange = isCountIfs === this.trueValue ? 0 : 2;
2898
+ for (var i = startRange; i < cellRanges.length; i++) {
2899
+ isCriteria = this.trueValue;
2900
+ isCriteria = isCountIfs === this.trueValue && i === 0 ? this.falseValue : this.trueValue;
2901
+ cellvalue = this.getCellCollection(cellRanges[i]);
2902
+ var sCell = {
2903
+ cellValue: cellvalue, cellRange: cellRanges, criteria: criterias,
2904
+ argArray: argArr, isCriteria: isCriteria, storedCells: storedCell, isCountIfS: isCountIfs, countVal: i
2905
+ };
2906
+ storedCell = this.computeStoreCells(sCell);
2907
+ storedCellLength = storedCell.length;
2908
+ if (storedCellLength === 0) {
2909
+ return isAvgIfs === this.trueValue ? this.getErrorStrings()[CommonErrors.DivZero] : 0;
2910
+ }
2911
+ }
2912
+ var avgValCount = 0;
2913
+ var sumRangeIndexes = cellRanges[0].indexOf('!') > -1 ?
2914
+ getRangeIndexes(cellRanges[0].substring(cellRanges[0].lastIndexOf('!') + 1)) : getRangeIndexes(cellRanges[0]);
2915
+ var lastCriteria = cellRanges[cellRanges.length - 1];
2916
+ var criteriaRangeIndexes = lastCriteria.indexOf('!') > -1 ?
2917
+ getRangeIndexes(lastCriteria.substring(lastCriteria.lastIndexOf('!') + 1)) : getRangeIndexes(lastCriteria);
2918
+ for (var j = 0; j < storedCell.length; j++) {
2919
+ // convert the new cell ranges for find sum in range 0(first range)
2920
+ var cell = '';
2921
+ var newCell = '';
2922
+ var count = 0;
2923
+ var newCount = 0;
2924
+ cell = storedCell[j];
2925
+ var isCriteriaFromOtherSheet = cell.indexOf('!') > -1;
2926
+ var isSumFromOtherSheet = void 0;
2927
+ var sumRangeSheet = '';
2928
+ var criteriaRangeSheet = '';
2929
+ if (isCriteriaFromOtherSheet) {
2930
+ criteriaRangeSheet = cell.substring(0, cell.lastIndexOf('!') + 1);
2931
+ cell = cell.substring(cell.lastIndexOf('!') + 1);
2932
+ }
2933
+ while (!this.isDigit(cell[count])) {
2934
+ count = count + 1;
2935
+ }
2936
+ if (this.isCellReference(cellRanges[0]) && cellRanges[0].indexOf(':') > -1) {
2937
+ newCell = getCellAddress(sumRangeIndexes[0] + (getCellIndexes(cell)[0] - criteriaRangeIndexes[0]), sumRangeIndexes[1] + (getCellIndexes(cell)[1] - criteriaRangeIndexes[1]));
2938
+ isSumFromOtherSheet = cellRanges[0].indexOf('!') > -1;
2939
+ if (isSumFromOtherSheet) {
2940
+ sumRangeSheet = cellRanges[0].substring(0, cellRanges[0].lastIndexOf('!') + 1);
2941
+ }
2942
+ while (!this.isDigit(newCell[newCount])) {
2943
+ newCount = newCount + 1;
2944
+ }
2945
+ }
2946
+ var cellAlpha = this.substring(cell, count);
2947
+ var newCellAlpha = this.substring(newCell, newCount);
2948
+ var cellNumeric = this.substring(cell, count, cell.length - count);
2949
+ var newCellNumeric = this.substring(newCell, newCount, newCell.length - count);
2950
+ if (isCriteriaFromOtherSheet) {
2951
+ cellAlpha = criteriaRangeSheet + cellAlpha;
2952
+ newCellAlpha = criteriaRangeSheet + newCellAlpha;
2953
+ }
2954
+ if (cellNumeric !== newCellNumeric) {
2955
+ storedCell[j] = this.substring(storedCell[j], isCriteriaFromOtherSheet ? (criteriaRangeSheet.length + count) : count) + newCellNumeric;
2956
+ }
2957
+ cellvalue = storedCell[j].split(cellAlpha).join(newCellAlpha);
2958
+ if (isSumFromOtherSheet) {
2959
+ if (cellvalue.indexOf('!') > -1) {
2960
+ cellvalue = cellvalue.substring(cellvalue.lastIndexOf('!') + 1);
2961
+ }
2962
+ cellvalue = sumRangeSheet + cellvalue;
2963
+ }
2964
+ else {
2965
+ cellvalue = cellvalue.substring(cellvalue.lastIndexOf('!') + 1);
2966
+ }
2967
+ if (isCountIfs === this.trueValue) {
2968
+ sum = sum + 1;
2969
+ }
2970
+ else {
2971
+ var argValue = this.getValueFromArg(cellvalue);
2972
+ var newArgValue = parseFloat(argValue === '' && isAvgIfs !== this.trueValue ? '0' : argValue);
2973
+ if (this.isNumber(newArgValue)) {
2974
+ avgValCount++;
2975
+ sum = sum + newArgValue;
2976
+ }
2977
+ }
2978
+ }
2979
+ if (isAvgIfs === this.trueValue) {
2980
+ sum = sum / avgValCount;
2981
+ }
2982
+ return sum;
2983
+ };
2984
+ /**
2985
+ * Shared COUNTIFS evaluation entry point.
2986
+ *
2987
+ * @param {string} range - COUNTIFS argument tokens.
2988
+ * @returns {string} - Count result or error token.
2989
+ * @hidden
2990
+ */
2991
+ Calculate.prototype.computeCountIfsFormulas = function (range) {
2992
+ var prevGrid = this.grid;
2993
+ if (isNullOrUndefined(range) || range[0] === '' || range.length < 2 || range.length > 127 ||
2994
+ range.length % 2 !== 0) {
2995
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
2996
+ }
2997
+ var argArr = range;
2998
+ var cellRanges = [];
2999
+ var criterias = [];
3000
+ for (var i = 0; i < argArr.length; i++) {
3001
+ if (i % 2 === 0 && this.isCellReference(argArr[i])) {
3002
+ cellRanges.push(argArr[i].indexOf(':') > -1 ?
3003
+ argArr[i].trim() : getRangeAddress(getRangeIndexes(argArr[i])));
3004
+ }
3005
+ else {
3006
+ criterias.push(argArr[i].trim());
3007
+ }
3008
+ }
3009
+ if (cellRanges.length !== criterias.length) {
3010
+ return this.getErrorStrings()[CommonErrors.Value];
3011
+ }
3012
+ var rangeIndexesArr = [];
3013
+ var grid = this.grid;
3014
+ for (var i = 0; i < cellRanges.length; i++) {
3015
+ var _a = getRangeIndexes(cellRanges[i]), startRow = _a[0], startCol = _a[1], endRow = _a[2], endCol = _a[3];
3016
+ var sheetToken = '';
3017
+ var family = this.getSheetFamilyItem(grid);
3018
+ if (cellRanges[i].startsWith('!')) {
3019
+ sheetToken = cellRanges[i].substring(0, cellRanges[i].replace('!', '').indexOf('!') + 2);
3020
+ if (family.tokenToParentObject !== null) {
3021
+ grid = family.tokenToParentObject.get(sheetToken);
3022
+ }
3023
+ }
3024
+ else if (family.parentObjectToToken !== null) {
3025
+ sheetToken = family.parentObjectToToken.get(grid);
3026
+ }
3027
+ this.grid = grid;
3028
+ var sheetId = this.getSheetId(grid);
3029
+ var sheetInfo = this.getHostSheetInfo();
3030
+ if (getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
3031
+ this.grid = prevGrid;
3032
+ return this.getErrorStrings()[CommonErrors.Ref];
3033
+ }
3034
+ var getCellValue = this.getCellValueFn(grid, this.cell, sheetId, true);
3035
+ if (rangeIndexesArr.length > 0) {
3036
+ var baseRange = rangeIndexesArr[rangeIndexesArr.length - 1];
3037
+ var baseRowCount = baseRange.endRow - baseRange.startRow + 1;
3038
+ var baseColCount = baseRange.endCol - baseRange.startCol + 1;
3039
+ if ((endRow - startRow + 1) !== baseRowCount || (endCol - startCol + 1) !== baseColCount) {
3040
+ return this.getErrorStrings()[CommonErrors.Value];
3041
+ }
3042
+ }
3043
+ rangeIndexesArr.push({ startRow: startRow, startCol: startCol, endRow: endRow, endCol: endCol, getCellValue: getCellValue, grid: grid });
3044
+ }
3045
+ for (var k = 0; k < criterias.length; k++) {
3046
+ if (criterias[k] === '') {
3047
+ this.grid = prevGrid;
3048
+ return 0;
3049
+ }
3050
+ }
3051
+ var filteredCells = [];
3052
+ for (var i = 0; i < rangeIndexesArr.length; i++) {
3053
+ this.grid = prevGrid;
3054
+ var criteria = criterias[i];
3055
+ var isStringVal = criteria.startsWith(this.tic) && criteria.endsWith(this.tic);
3056
+ criteria = this.getANDComputedValue(criteria.trim());
3057
+ var isAsterisk = criteria.includes('*');
3058
+ var isAsteriskOnly = criteria === '*' || criteria === '<>*';
3059
+ var criteriaValue = isAsterisk && !isAsteriskOnly ? criteria.replace(/\*/g, '').trim() : criteria;
3060
+ var isCellReferenceValue = false;
3061
+ if (!isStringVal && this.isCellReference(criteriaValue)) {
3062
+ criteriaValue = this.getValueFromArg(criteriaValue);
3063
+ isCellReferenceValue = true;
3064
+ }
3065
+ if (isAsterisk && !isAsteriskOnly) {
3066
+ var asteriskIndex = criteria.indexOf('*');
3067
+ if (criteria[0] === '*') {
3068
+ criteriaValue = '*' + criteriaValue;
3069
+ }
3070
+ if (criteria[criteria.length - 1] === '*') {
3071
+ criteriaValue += '*';
3072
+ }
3073
+ if (asteriskIndex > 0 && asteriskIndex < criteria.length - 1) {
3074
+ criteriaValue = criteria.substring(0, asteriskIndex) + '*' + criteria.substring(asteriskIndex + 1);
3075
+ }
3076
+ }
3077
+ criteria = criteriaValue;
3078
+ var op = 'equal';
3079
+ var updatedCriteria = this.getOperatorAndCriteria(criteria, op);
3080
+ op = updatedCriteria.op;
3081
+ criteria = updatedCriteria.criteria;
3082
+ if ((!isStringVal && this.isCellReference(criteria) && !isCellReferenceValue) || criteria.includes(this.arithMarker)) {
3083
+ criteria = this.getValueFromArg(criteria);
3084
+ }
3085
+ var hasWildCards = criteria.indexOf('*') > -1 || criteria.indexOf('?') > -1;
3086
+ var _b = rangeIndexesArr[i], startRow = _b.startRow, startCol = _b.startCol, endRow = _b.endRow, endCol = _b.endCol, getCellValue = _b.getCellValue;
3087
+ var rangeGrid = rangeIndexesArr[i].grid;
3088
+ this.grid = rangeGrid;
3089
+ var cellVal = void 0;
3090
+ if (i === 0) {
3091
+ for (var r = startRow; r <= endRow; r++) {
3092
+ for (var c = startCol; c <= endCol; c++) {
3093
+ cellVal = getCellValue(r + 1, c + 1, getCellAddress(r, c));
3094
+ if (hasWildCards) {
3095
+ cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
3096
+ }
3097
+ if (this.processLogical([cellVal.toLowerCase(), criteria.toLowerCase()], op) === this.trueValue) {
3098
+ filteredCells.push({ rowIdx: r, colIdx: c });
3099
+ }
3100
+ }
3101
+ }
3102
+ }
3103
+ else {
3104
+ var storedCells = filteredCells;
3105
+ var previousRangeIdx = rangeIndexesArr[i - 1];
3106
+ filteredCells = [];
3107
+ for (var j = 0; j < storedCells.length; j++) {
3108
+ var updatedCell = storedCells[j];
3109
+ updatedCell.rowIdx = startRow + (updatedCell.rowIdx - previousRangeIdx.startRow);
3110
+ updatedCell.colIdx = startCol + (updatedCell.colIdx - previousRangeIdx.startCol);
3111
+ cellVal = getCellValue(updatedCell.rowIdx + 1, updatedCell.colIdx + 1, getCellAddress(updatedCell.rowIdx, updatedCell.colIdx));
3112
+ if (hasWildCards) {
3113
+ cellVal = this.findWildCardValue(criteria.toLowerCase(), cellVal.toLowerCase());
3114
+ }
3115
+ if (this.processLogical([cellVal.toLowerCase(), criteria.toLowerCase()], op) === this.trueValue) {
3116
+ filteredCells.push({ rowIdx: updatedCell.rowIdx, colIdx: updatedCell.colIdx });
3117
+ }
3118
+ }
3119
+ }
3120
+ if (filteredCells.length === 0) {
3121
+ this.grid = prevGrid;
3122
+ return 0;
3123
+ }
3124
+ }
3125
+ this.grid = prevGrid;
3126
+ return filteredCells.length;
3127
+ };
3128
+ Calculate.prototype.getOperatorAndCriteria = function (rawCriteria, op) {
3129
+ var criteria = rawCriteria;
3130
+ if (criteria.startsWith('<=')) {
3131
+ op = 'lessEq';
3132
+ criteria = criteria.substring(2);
3133
+ }
3134
+ else if (criteria.startsWith('>=')) {
3135
+ op = 'greaterEq';
3136
+ criteria = criteria.substring(2);
3137
+ }
3138
+ else if (criteria.startsWith('<>')) {
3139
+ op = 'notEq';
3140
+ criteria = criteria.substring(2);
3141
+ }
3142
+ else if (criteria.startsWith('<')) {
3143
+ op = 'less';
3144
+ criteria = criteria.substring(1);
3145
+ }
3146
+ else if (criteria.startsWith('>')) {
3147
+ op = 'greater';
3148
+ criteria = criteria.substring(1);
3149
+ }
3150
+ else if (criteria.startsWith('=')) {
3151
+ op = 'equal';
3152
+ criteria = criteria.substring(1);
3153
+ }
3154
+ return { op: op, criteria: criteria };
3155
+ };
3156
+ Calculate.prototype.processNestedFormula = function (pText, sFormula, fResult) {
3157
+ if (fResult && !fResult.toString().includes('"')) {
3158
+ var formulaEndIdx = pText.indexOf(sFormula) + sFormula.length;
3159
+ if (pText[formulaEndIdx] === '"' && this.getErrorStrings().indexOf(fResult.toString()) < 0 &&
3160
+ !this.isNumber(fResult) && fResult !== this.trueValue && fResult !== this.falseValue) {
3161
+ return pText.split(sFormula).join('"' + fResult + '"');
3162
+ }
3163
+ }
3164
+ return pText.split(sFormula).join('n' + fResult);
3165
+ };
3166
+ /**
3167
+ * Returns whether `value` is `NaN` after numeric coercion.
3168
+ *
3169
+ * @hidden
3170
+ * @param {string | number | boolean | Object} value - Value to test.
3171
+ * @returns {number} - `true` when not a number.
3172
+ */
3173
+ Calculate.prototype.isNaN = function (value) {
3174
+ if (value.toString() === 'NaN' || typeof value === 'string') {
3175
+ return true;
3176
+ }
3177
+ return false;
3178
+ };
3179
+ /**
3180
+ * Returns whether `val` is numeric (including numeric strings).
3181
+ *
3182
+ * @hidden
3183
+ * @param {string | number} val - Value to test.
3184
+ * @returns {number} - `true` when numeric.
3185
+ */
3186
+ Calculate.prototype.isNumber = function (val) {
3187
+ return val - parseFloat(val) >= 0;
3188
+ };
3189
+ /**
3190
+ * Converts an OLE Automation (Excel) serial date to a JavaScript `Date`.
3191
+ *
3192
+ * @hidden
3193
+ * @param {string | number | Object} doubleNumber - Excel serial date/time.
3194
+ * @returns {Date | Object} - JavaScript `Date`.
3195
+ */
3196
+ Calculate.prototype.fromOADate = function (doubleNumber) {
3197
+ doubleNumber = (doubleNumber > 0 && doubleNumber < 1) ? (1 + doubleNumber) : (doubleNumber === 0) ? 1 : doubleNumber;
3198
+ if (doubleNumber > 60) {
3199
+ doubleNumber -= 1; // Due to leap year issue of 1900 in MSExcel.
3200
+ }
3201
+ var result = new Date('01/01/1900');
3202
+ var resultDateUTC = Date.UTC(result.getFullYear(), result.getMonth(), result.getDate(), result.getHours(), result.getMinutes(), result.getSeconds(), result.getMilliseconds());
3203
+ return new Date(new Date(((doubleNumber - 1) * (this.millisecondsOfaDay)) + resultDateUTC).toUTCString().replace(' GMT', ''));
3204
+ };
3205
+ /**
3206
+ * Builds an Excel serial date from year, month, and day components.
3207
+ *
3208
+ * @hidden
3209
+ * @param {number} year - Full year.
3210
+ * @param {number} month - Month number (1–12; Excel-style overflow allowed).
3211
+ * @param {number} day - Day of month (Excel-style overflow allowed).
3212
+ * @returns {number} - Excel serial date number.
3213
+ */
3214
+ Calculate.prototype.getSerialDateFromDate = function (year, month, day) {
3215
+ var days = 0;
3216
+ if (year < 1900) {
3217
+ year += 1900;
3218
+ }
3219
+ var isValidMonth = false;
3220
+ while (!isValidMonth) {
3221
+ while (month > 12) {
3222
+ year++;
3223
+ month -= 12;
3224
+ }
3225
+ while (month < 1) {
3226
+ month += 12;
3227
+ year--;
3228
+ }
3229
+ isValidMonth = true;
3230
+ var tempDay = new Date(year, month, 1, -1).getDate();
3231
+ while (day > tempDay) {
3232
+ tempDay = new Date(year, month, 1, -1).getDate();
3233
+ month++;
3234
+ day -= tempDay;
3235
+ isValidMonth = false;
3236
+ }
3237
+ if (day < 1) {
3238
+ month--;
3239
+ if (month < 1) {
3240
+ month = 12;
3241
+ year--;
3242
+ }
3243
+ tempDay = new Date(year, month, 1, -1).getDate();
3244
+ day = tempDay + day;
3245
+ isValidMonth = false;
3246
+ }
3247
+ }
3248
+ var dateTime = Date.parse(year + "/" + month + "/" + day);
3249
+ if (!this.isNaN(dateTime)) {
3250
+ days = this.toOADate(new Date(dateTime));
3251
+ }
3252
+ return days;
3253
+ };
3254
+ /**
3255
+ * Converts a serial time fraction (or time string) to a `Date`.
3256
+ *
3257
+ * @param {string | number | boolean | Object} value - Time serial or text.
3258
+ * @returns {Date | Object} - `Date` representing the time of day.
3259
+ * @hidden
3260
+ */
3261
+ Calculate.prototype.intToTime = function (value) {
3262
+ var val = value.toString().split('.');
3263
+ if (!isNullOrUndefined(val[1])) {
3264
+ value = parseFloat(val[0] + 1 + '.' + val[1]) || value;
3265
+ }
3266
+ return this.intToDate(value.toString());
3267
+ };
3268
+ /**
3269
+ * Converts a JavaScript `Date` to an Excel OLE Automation serial number.
3270
+ *
3271
+ * @hidden
3272
+ * @param {string | number | Object} dateTime - Date/time to convert.
3273
+ * @param {boolean} isTime - When `true`, includes the time fraction.
3274
+ * @param {boolean} isTimeOnly - When `true`, treats the value as time without a date component.
3275
+ * @returns {number} - Excel serial number.
3276
+ */
3277
+ Calculate.prototype.toOADate = function (dateTime, isTime, isTimeOnly) {
3278
+ var startDate = new Date('01/01/1900');
3279
+ var date = isDateTime(dateTime) ? dateTime : new Date(dateTime);
3280
+ var startDateUTC = Date.UTC(startDate.getFullYear(), startDate.getMonth(), startDate.getDate(), startDate.getHours(), startDate.getMinutes(), startDate.getSeconds(), startDate.getMilliseconds());
3281
+ var dateUTC = Date.UTC(date.getFullYear(), date.getMonth(), date.getDate(), date.getHours(), date.getMinutes(), date.getSeconds(), date.getMilliseconds());
3282
+ var diffDays = ((dateUTC - startDateUTC) / (1000 * 3600 * 24));
3283
+ return (isTime ? diffDays : parseInt(diffDays.toString(), 10)) + (isTimeOnly ? 0 : (diffDays > 60 ? 2 : 1));
3284
+ };
3285
+ /**
3286
+ * Normalizes a date string for calculation.
3287
+ *
3288
+ * @param {number | string} date - Date text.
3289
+ * @returns {string} - Normalized date string.
3290
+ * @hidden
3291
+ */
3292
+ Calculate.prototype.calculateDate = function (date) {
3293
+ return (this.parseFloat(date) < 10) ? '0' + date : date;
3294
+ };
3295
+ /**
3296
+ * Returns whether `s` is `null`, `undefined`, or an empty string.
3297
+ *
3298
+ * @hidden
3299
+ * @param {number | string} s - Text to test.
3300
+ * @returns {string | number} - `true` when empty.
3301
+ */
3302
+ Calculate.prototype.isTextEmpty = function (s) {
3303
+ return s === null || s === '';
3304
+ };
3305
+ /**
3306
+ * Returns whether `text` consists only of digit characters `0`–`9`.
3307
+ *
3308
+ * @hidden
3309
+ * @param {string} text - Text to test.
3310
+ * @returns {string | number} - `true` when all characters are digits.
3311
+ */
3312
+ Calculate.prototype.isDigit = function (text) {
3313
+ var charCode = text.charCodeAt(0);
3314
+ return charCode > 47 && charCode < 58;
3315
+ };
3316
+ /**
3317
+ * Evaluates a single AND condition token to `"TRUE"` / `"FALSE"`.
3318
+ *
3319
+ * @param {boolean | string | number} condition - Condition expression or cell token.
3320
+ * @returns {string} - Logical result string.
3321
+ * @hidden
3322
+ */
3323
+ Calculate.prototype.getANDComputedValue = function (condition) {
3324
+ if (condition.startsWith(this.arithMarker) && condition.includes('c')) {
3325
+ condition = this.getValueFromArg(condition);
3326
+ }
3327
+ return condition.split(this.tic).join('');
3328
+ };
3329
+ Calculate.prototype.findLastIndexOfq = function (fString) {
3330
+ var lastIndexOfq = fString.lastIndexOf('q');
3331
+ var lastIndexOflLeftBracket = fString.lastIndexOf(this.leftBracket);
3332
+ while (lastIndexOflLeftBracket < lastIndexOfq) {
3333
+ lastIndexOfq = fString.substring(0, lastIndexOfq).lastIndexOf('q');
3334
+ }
3335
+ return lastIndexOfq;
3336
+ };
3337
+ /**
3338
+ * Resolves a formula argument token to its computed display/value string.
3339
+ *
3340
+ * Handles cell references, nested formulas, literals, and named ranges.
3341
+ *
3342
+ * @hidden
3343
+ * @param {string | number} val - Argument token from the parser.
3344
+ * @param {boolean} isUnique - UNIQUE formula context.
3345
+ * @param {boolean} isIfError - IFERROR/IFNA context.
3346
+ * @param {boolean} isSubtotal - SUBTOTAL context.
3347
+ * @param {boolean} isIFFormula - IF formula context.
3348
+ * @returns {string} - Resolved value string.
3349
+ */
3350
+ Calculate.prototype.getValueFromArg = function (val, isUnique, isIfError, isSubtotal, isIFFormula) {
3351
+ val = val.trim();
3352
+ if (!val || this.getErrorStrings().indexOf(val) > -1) {
3353
+ return val;
3354
+ }
3355
+ var firstChar = val[0];
3356
+ if (firstChar === this.tic || firstChar === this.singleTic) {
3357
+ var parsedVal = val.split(this.tic).join('');
3358
+ if (this.isNaN(this.parseFloat(parsedVal)) && !(isIFFormula && firstChar === this.tic && val.endsWith(this.tic))) {
3359
+ var dateTime = this.isDate(parsedVal);
3360
+ if (dateTime && !this.isNaN(dateTime.getDate())) {
3361
+ return this.toOADate(dateTime, true).toString();
3362
+ }
3363
+ }
3364
+ if (val.endsWith(this.tic)) {
3365
+ var decimalSep = this.getParseDecimalSeparator();
3366
+ if (decimalSep !== '.' && parsedVal.includes(decimalSep)) {
3367
+ parsedVal = parsedVal.replace(decimalSep, '.');
3368
+ if (this.isNumber(parsedVal)) {
3369
+ val = parsedVal;
3370
+ }
3371
+ }
3372
+ }
3373
+ return val;
3374
+ }
3375
+ else if (firstChar === 'u' && val.includes(this.arithMarker)) {
3376
+ // To parse - sign with brackets, cell references and nested formulas in the formula arguments. Ex: -(I13+I14+I12)/(-D2+D1) as arguments in formulas.
3377
+ val = this.parser.parseSimpleOperators(val.split('u').join('0-'), [this.parser.tokenSubtract], ['-']);
3378
+ }
3379
+ else {
3380
+ var isFirstCharUpper = this.isUpperChar(firstChar);
3381
+ if (!isFirstCharUpper) {
3382
+ var decimalSep = this.getParseDecimalSeparator();
3383
+ if (this.isDigit(firstChar) || firstChar === decimalSep || firstChar === '-' || firstChar === 'n') {
3384
+ if (firstChar === 'n') {
3385
+ val = val.substring(1);
3386
+ if (val.indexOf('"n') > -1) {
3387
+ val = val.replace('"n', '"');
3388
+ }
3389
+ }
3390
+ if (decimalSep !== '.' && val.includes(decimalSep)) {
3391
+ var parsedVal = val.replace(decimalSep, '.');
3392
+ if (this.isNumber(parsedVal)) {
3393
+ val = parsedVal;
3394
+ }
3395
+ }
3396
+ return val;
3397
+ }
3398
+ }
3399
+ }
3400
+ var tokenAvail = firstChar === this.sheetToken;
3401
+ if (tokenAvail || (this.isUpperChar(firstChar) && !['+', '-', '/', '*', ')', ')', '{'].some(function (opr) { return val.includes(opr); }))) {
3402
+ var isCellRef = this.isCellReference(val);
3403
+ if (isCellRef && !tokenAvail) {
3404
+ var family = this.getSheetFamilyItem(this.grid);
3405
+ if (family.sheetNameToParentObject !== null && family.parentObjectToToken.has(this.grid)) {
3406
+ val = family.parentObjectToToken.get(this.grid) + val;
3407
+ }
3408
+ }
3409
+ if (val === this.cell) {
3410
+ var dependent = this.getDependentCells().get(val);
3411
+ if (dependent != null && dependent.indexOf(val) > -1) {
3412
+ this.arrayRemove(dependent, val);
3413
+ }
3414
+ if (!this.getDependentFormulaCells().has(this.cell)) {
3415
+ this.clearFormulaDependentCells(this.cell);
3416
+ }
3417
+ if (!isUnique) {
3418
+ throw new FormulaError(this.formulaErrorStrings[FormulasErrorsStrings.CircularReference]);
3419
+ }
3420
+ }
3421
+ var cellValue = this.getParentObjectCellValue(val, false, isUnique, isSubtotal);
3422
+ var result = isNullOrUndefined(cellValue) ? '' : cellValue.toString();
3423
+ if (isCellRef) {
3424
+ this.updateDependentCell(val);
3425
+ }
3426
+ return result;
3427
+ }
3428
+ else {
3429
+ return this.computeValue(val, false, isIfError);
3430
+ }
3431
+ };
3432
+ /**
3433
+ * Attempts to interpret `date` as a JavaScript `Date`.
3434
+ *
3435
+ * @hidden
3436
+ * @param {number | string} date - Date instance, serial, or valid text.
3437
+ * @returns {Date | Object} - `Date` when recognized; otherwise a false result used by callers.
3438
+ */
3439
+ Calculate.prototype.isDate = function (date) {
3440
+ if (typeof date === 'object' || Date.parse(date) !== null) {
3441
+ var dateVal = void 0;
3442
+ if (typeof date === 'string') {
3443
+ dateVal = this.checkDateFormat(date, false, true);
3444
+ }
3445
+ else {
3446
+ dateVal = new Date(Date.parse(date));
3447
+ }
3448
+ if (dateVal >= this.dateTime1900) {
3449
+ return dateVal;
3450
+ }
3451
+ else {
3452
+ return null;
3453
+ }
3454
+ }
3455
+ else {
3456
+ return null;
3457
+ }
3458
+ };
3459
+ /**
3460
+ * Parses a date-like value into a `Date` or intermediate representation.
3461
+ *
3462
+ * @param {number | string} date - Value to parse.
3463
+ * @returns {string | number} - Parsed date information.
3464
+ * @hidden
3465
+ */
3466
+ Calculate.prototype.parseDate = function (date) {
3467
+ if (!this.isNaN(date)) {
3468
+ if (date instanceof Date) {
3469
+ return new Date(date);
3470
+ }
3471
+ var d = parseInt(date, 10);
3472
+ if (d < 0) {
3473
+ return this.getErrorStrings()[CommonErrors.Num];
3474
+ }
3475
+ if (d <= 60) {
3476
+ return new Date(this.dateTime1900.getTime() + (d - 1) * 86400000);
3477
+ }
3478
+ return new Date(this.dateTime1900.getTime() + (d - 2) * 86400000);
3479
+ }
3480
+ if (typeof date === 'string') {
3481
+ date = this.checkDateFormat(date, true);
3482
+ if (!this.isNaN(date)) {
3483
+ return date;
3484
+ }
3485
+ }
3486
+ return this.getErrorStrings()[CommonErrors.Value];
3487
+ };
3488
+ /**
3489
+ * Validates and parses a date string using engine/host date rules.
3490
+ *
3491
+ * @param {number | string} date - Date text.
3492
+ * @param {string | number | Object} pvtParse - Private parse mode.
3493
+ * @param {string | number | Object} fromIsDate - When called from {@link isDate}.
3494
+ * @returns {Date | Object} - Parsed `Date` when valid.
3495
+ * @hidden
3496
+ */
3497
+ Calculate.prototype.checkDateFormat = function (date, pvtParse, fromIsDate) {
3498
+ var host = this.parentObject;
3499
+ if (host && typeof host.getModuleName === 'function' && host.getModuleName() === 'spreadsheet') {
3500
+ var dateEventArgs = this.hostParseDate(date);
3501
+ if (dateEventArgs.isDate) {
3502
+ return dateEventArgs.dateObj;
3503
+ }
3504
+ else if (fromIsDate && !dateEventArgs.isTime) {
3505
+ return new Date(NaN);
3506
+ }
3507
+ }
3508
+ if (this.getErrorStrings().indexOf(date) > -1) {
3509
+ return new Date(NaN);
3510
+ }
3511
+ if (!pvtParse) {
3512
+ return new Date(Date.parse(date));
3513
+ }
3514
+ return new Date(date);
3515
+ };
3516
+ /**
3517
+ * Returns whether `args` looks like a valid cell or range reference.
3518
+ *
3519
+ * @hidden
3520
+ * @param {string[]} args - Text to test.
3521
+ * @returns {string} - `true` when the text is a cell/range reference.
3522
+ */
3523
+ Calculate.prototype.isCellReference = function (args) {
3524
+ args = args.trim();
3525
+ if (args === '') {
3526
+ return false;
3527
+ }
3528
+ args = this.setTokensForSheets(args);
3529
+ var sheetToken1 = this.getSheetToken(args);
3530
+ var containsBoth = false;
3531
+ if (sheetToken1 !== '') {
3532
+ args = args.split(sheetToken1).join('');
3533
+ }
3534
+ var isAlpha = false;
3535
+ var isNum = false;
3536
+ if (args.indexOf(':') !== args.lastIndexOf(':')) {
3537
+ return false;
3538
+ }
3539
+ var charArray = (args.split('').join(this.getParseArgumentSeparator())).split(this.getParseArgumentSeparator());
3540
+ for (var c = 0; c < charArray.length; c++) {
3541
+ if (this.isChar(charArray[c])) {
3542
+ isAlpha = true;
3543
+ }
3544
+ else if (this.isDigit(charArray[c])) {
3545
+ isNum = true;
3546
+ }
3547
+ else if (charArray[c] === ':') {
3548
+ if (isAlpha && isNum) {
3549
+ containsBoth = true;
3550
+ }
3551
+ isAlpha = false;
3552
+ isNum = false;
3553
+ }
3554
+ else {
3555
+ return false;
3556
+ }
3557
+ }
3558
+ if (args.indexOf(':') > -1 && args.indexOf(this.tic) === -1) {
3559
+ if (((containsBoth && isAlpha && isNum) || (((isAlpha && !isNum) || (!isAlpha && isNum)) && !containsBoth))) {
3560
+ return true;
3561
+ }
3562
+ else {
3563
+ return false;
3564
+ }
3565
+ }
3566
+ if (isAlpha && isNum && args.indexOf(this.tic) === -1 && this.isValidCell(args)) {
3567
+ return true;
3568
+ }
3569
+ return false;
3570
+ };
3571
+ /**
3572
+ * Rewrites sheet names in formula text to internal sheet tokens.
3573
+ *
3574
+ * @param {string} text - Formula text containing sheet names.
3575
+ * @returns {string} - Text with sheet tokens substituted.
3576
+ * @hidden
3577
+ */
3578
+ Calculate.prototype.setTokensForSheets = function (text) {
3579
+ var family = this.getSheetFamilyItem(this.grid);
3580
+ var sortedSheetNamesCollection = this.getSortedSheetNames();
3581
+ if (sortedSheetNamesCollection != null) {
3582
+ for (var n = 0; n < sortedSheetNamesCollection.length; n++) {
3583
+ var token = family.sheetNameToToken.get(sortedSheetNamesCollection[n]);
3584
+ token = token.split(this.sheetToken).join(this.tempSheetPlaceHolder);
3585
+ var s = this.singleTic + 'SHEET' + sortedSheetNamesCollection[n] + this.singleTic + this.sheetToken;
3586
+ if (text.indexOf(s) === -1) {
3587
+ s = 'SHEET' + sortedSheetNamesCollection[n] + this.sheetToken;
3588
+ }
3589
+ text = text.split(s).join(token);
3590
+ s = sortedSheetNamesCollection[n] + this.sheetToken;
3591
+ text = text.split(s).join(token);
3592
+ }
3593
+ }
3594
+ text = text.split(this.tempSheetPlaceHolder).join(this.sheetToken);
3595
+ if (text.indexOf('!!') > -1) {
3596
+ text = text.replace('!!', '!');
3597
+ var textSplit = text.split('!');
3598
+ textSplit[1] = (parseInt(textSplit[1], 10) + 1).toString();
3599
+ text = textSplit.join('!');
3600
+ }
3601
+ return text;
3602
+ };
3603
+ Calculate.prototype.getParentObjectCellValue = function (val, refresh, isUnique, isSubtotal) {
3604
+ if (val === this.trueValue || val === this.falseValue) {
3605
+ return val;
3606
+ }
3607
+ var tokenIdx = val.lastIndexOf(this.sheetToken);
3608
+ var grid = this.grid;
3609
+ var cellRef;
3610
+ if (tokenIdx > -1) {
3611
+ var family = this.getSheetFamilyItem(grid);
3612
+ if (family.tokenToParentObject !== null) {
3613
+ this.grid = family.tokenToParentObject.get(val.substring(0, tokenIdx + 1));
3614
+ cellRef = val.substring(tokenIdx + 1);
3615
+ }
3616
+ else {
3617
+ return this.getErrorStrings()[CommonErrors.Value];
3618
+ }
3619
+ }
3620
+ else {
3621
+ var j = 0;
3622
+ while (j < val.length && this.isChar(val[j])) {
3623
+ j++;
3624
+ }
3625
+ if (j === val.length) {
3626
+ return val === '' ? this.getErrorStrings()[CommonErrors.Value] : this.getErrorStrings()[CommonErrors.Name];
3627
+ }
3628
+ else {
3629
+ cellRef = val;
3630
+ var family = this.getSheetFamilyItem(grid);
3631
+ if (family.isSheetMember && family.parentObjectToToken != null) {
3632
+ val = family.parentObjectToToken.get(this.grid) + val;
3633
+ }
3634
+ }
3635
+ }
3636
+ if (this.isDigit(cellRef[0])) {
3637
+ var alphabetStartIdx = cellRef.search(/[a-zA-Z]/);
3638
+ if (alphabetStartIdx > 0) {
3639
+ cellRef = cellRef.substring(alphabetStartIdx, cellRef.length) + cellRef.substring(0, alphabetStartIdx);
3640
+ }
3641
+ }
3642
+ var row = this.rowIndex(cellRef);
3643
+ var col = this.colIndex(cellRef);
3644
+ var result;
3645
+ if (!(row > 0 && row <= maxRows && col > 0 && col <= maxCols)) {
3646
+ result = this.getErrorStrings()[CommonErrors.Name];
3647
+ }
3648
+ else {
3649
+ var sheetId = this.getSheetId(this.grid);
3650
+ var sheetInfo = this.getHostSheetInfo();
3651
+ if (sheetInfo.length && getSheetIndexByName('Sheet' + sheetId, sheetInfo) === -1) {
3652
+ this.grid = grid;
3653
+ return this.getErrorStrings()[CommonErrors.Ref];
3654
+ }
3655
+ result = this.getCellValueFn(grid, this.cell, sheetId, false, refresh, isUnique, isSubtotal)(row, col, val);
3656
+ }
3657
+ this.grid = grid;
3658
+ return isNullOrUndefined(result) ? '' : result;
3659
+ };
3660
+ /**
3661
+ * Returns a function that reads a cell value for the active grid context.
3662
+ *
3663
+ * @param {Object} grid - Grid / parent object providing cell values.
3664
+ * @param {string} actCell - Active cell reference for dependency tracking.
3665
+ * @param {string | number | Object} sheetId - Sheet id for the grid.
3666
+ * @param {string} updateDependentCell - When `true`, records dependents while reading.
3667
+ * @param {string | number | Object} refresh - Whether to refresh computed values while reading.
3668
+ * @param {boolean} isUnique - UNIQUE formula context.
3669
+ * @param {boolean} isSubtotal - SUBTOTAL formula context.
3670
+ * @returns {string} - Cell value getter `(row, col, curCell) => string`.
3671
+ * @hidden
3672
+ */
3673
+ Calculate.prototype.getCellValueFn = function (grid, actCell, sheetId, updateDependentCell, refresh, isUnique, isSubtotal) {
3674
+ var _this = this;
3675
+ var fromCell = actCell;
3676
+ if (fromCell) {
3677
+ fromCell = grid === this.grid ? '' :
3678
+ fromCell + ',' + (typeof grid === 'string' && Number(grid) > -1 ? grid : this.getSheetID(grid));
3679
+ }
3680
+ var getValueRowCol = this.parentObject.getValueRowCol.bind(this.parentObject) ||
3681
+ this.getValueRowCol.bind(this);
3682
+ return function (row, col, curCell) {
3683
+ if (actCell === curCell && !isUnique) {
3684
+ throw _this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
3685
+ }
3686
+ _this.cell = curCell;
3687
+ var val = getValueRowCol(sheetId, row, col, fromCell, refresh, isUnique, isSubtotal);
3688
+ if (isNullOrUndefined(val)) {
3689
+ val = '';
3690
+ }
3691
+ else {
3692
+ val = val.toString();
3693
+ var decimalSep = _this.getParseDecimalSeparator();
3694
+ if (decimalSep !== '.' && val.includes(decimalSep)) {
3695
+ var parsedVal = val.replace(decimalSep, '.');
3696
+ if (_this.isNumber(parsedVal)) {
3697
+ val = parsedVal;
3698
+ }
3699
+ }
3700
+ }
3701
+ _this.cell = actCell;
3702
+ if (updateDependentCell) {
3703
+ _this.updateDependentCell(curCell);
3704
+ }
3705
+ return val;
3706
+ };
3707
+ };
3708
+ Calculate.prototype.isValidCell = function (args) {
3709
+ var digitStartIdx = args.search(/\d/);
3710
+ if (digitStartIdx === 0) {
3711
+ var alphabetStartIdx = args.search(/[a-zA-Z]/);
3712
+ args = args.substring(alphabetStartIdx, args.length) + args.substring(0, alphabetStartIdx);
3713
+ }
3714
+ var row = this.rowIndex(args);
3715
+ var col = this.colIndex(args);
3716
+ return row > 0 && row <= maxRows && col > 0 && col <= maxCols;
3717
+ };
3718
+ /**
3719
+ * Returns the numeric sheet id for a registered grid object.
3720
+ *
3721
+ * @param {Object} grd - Grid / parent object.
3722
+ * @returns {string | number} - Sheet id.
3723
+ * @hidden
3724
+ */
3725
+ Calculate.prototype.getSheetId = function (grd) {
3726
+ return grd && typeof grd === 'string' && Number(grd) > -1 ? Number(grd) : this.getSheetID(grd) + 1;
3727
+ };
3728
+ /**
3729
+ * Getting the formula result.
3730
+ *
3731
+ * @param {Object} grid - Specifies the parent object.
3732
+ * @param {number} row - Row index of the parent object or key.
3733
+ * @param {number} col - Column index of the parent object.
3734
+ * @returns {string} - Getting the formula result.
3735
+ */
3736
+ /**
3737
+ * Reads a cell value from a grid at 1-based row/column indexes.
3738
+ *
3739
+ * @param {Object} grid - Grid / parent object.
3740
+ * @param {number} row - 1-based row index.
3741
+ * @param {number} col - 1-based column index.
3742
+ * @returns {string} - Cell value as a string.
3743
+ */
3744
+ Calculate.prototype.getValueRowCol = function (grid, row, col) {
3745
+ var address = (this.convertAlpha(col) + row.toString()).toUpperCase();
3746
+ if (this.storedData.has(address)) {
3747
+ var addressValue = this.getKeyValue(address);
3748
+ return isNullOrUndefined(addressValue) ? '' : addressValue.toString();
3749
+ }
3750
+ var mappedKey = this.rowsToKeyMap.get(row);
3751
+ if (isNullOrUndefined(mappedKey)) {
3752
+ return '';
3753
+ }
3754
+ var key = mappedKey.toString();
3755
+ var keyUpper = key.toUpperCase();
3756
+ // Row map is insertion-order based; ignore when it points at a different A1 cell.
3757
+ if (this.isCellReference(keyUpper) && keyUpper !== address) {
3758
+ return '';
3759
+ }
3760
+ // Avoid re-entering a formula key already on the getKeyValue evaluation stack.
3761
+ if (this.evaluatingKeys.has(keyUpper)) {
3762
+ return '';
3763
+ }
3764
+ var result = this.getKeyValue(key);
3765
+ if (isNullOrUndefined(result)) {
3766
+ return '';
3767
+ }
3768
+ result = result.toString();
3769
+ if (result !== '' && result[result.length - 1] === '%' && result.length > 1) {
3770
+ var d = this.parseFloat(result.substring(0, result.length - 1));
3771
+ if (this.isNaN(d)) {
3772
+ result = (Number(d) / 100).toString();
3773
+ }
3774
+ }
3775
+ return result;
3776
+ };
3777
+ /**
3778
+ * Registers a custom formula in the library.
3779
+ *
3780
+ * @param {string} formulaName - Excel-facing function name to register.
3781
+ * @param {string} functionName - Handler function, or a global function name string.
3782
+ * @param {string | number | Object} formulaDescription - Description shown in Insert Function UI.
3783
+ * @param {string} category - Category label for Insert Function UI.
3784
+ *
3785
+ * @example
3786
+ * ```ts
3787
+ * engine.defineFunction('DOUBLE', (x) => Number(x) * 2, 'Doubles a number', 'Custom');
3788
+ * ```
3789
+ * @returns {void}
3790
+ */
3791
+ Calculate.prototype.defineFunction = function (formulaName, functionName, formulaDescription, category) {
3792
+ if (typeof functionName === 'string') {
3793
+ functionName = getValue(functionName, window);
3794
+ }
3795
+ formulaName = formulaName.toUpperCase();
3796
+ this.libraryFormulas.set(formulaName, {
3797
+ handler: functionName, isCustom: true,
3798
+ description: formulaDescription, category: category
3799
+ });
3800
+ };
3801
+ /**
3802
+ * Notifies the engine that a cell value or formula changed and optionally recalculates dependents.
3803
+ *
3804
+ * @hidden
3805
+ * @param {Object} grid - Parent object / sheet reference name.
3806
+ * @param {string[]} changeArgs - Changed cell coordinates and formula/value.
3807
+ * @param {boolean} isCalculate - When `true`, recalculates the changed formula.
3808
+ * @param {string | number | Object} usedRangeCol - Used-range bounds for the sheet.
3809
+ * @param {string | number | Object} refresh - Whether to refresh computed values.
3810
+ * @param {string} sheetName - Visible sheet name for `actCell` tracking.
3811
+ * @param {boolean} isRandomFormula - Whether the change involves volatile random formulas.
3812
+ * @param {string} randomFormulaRefreshing - Whether random formulas are being refreshed.
3813
+ * @param {boolean} isDelete - Whether the change originates from a delete operation.
3814
+ * @param {string} deletedRange - Deleted range indexes when `isDelete` is `true`.
3815
+ * @param {string | number | Object} refreshDependentCells - Forces dependent refresh regardless of calculation mode.
3816
+ * @param {string | number | Object} action - Optional calculation action label (for example `"calculate"`).
3817
+ */
3818
+ Calculate.prototype.valueChanged = function (grid, changeArgs, isCalculate, usedRangeCol, refresh, sheetName, isRandomFormula, randomFormulaRefreshing, isDelete, deletedRange, refreshDependentCells, action) {
3819
+ var pgrid = grid;
3820
+ this.spreadSheetUsedRange = usedRangeCol;
3821
+ this.grid = grid;
3822
+ var isComputedValueChanged = true;
3823
+ var isCompute = true;
3824
+ var calcFamily = this.getSheetFamilyItem(pgrid);
3825
+ var cellTxt = getAlphalabel(changeArgs.getColIndex()) + changeArgs.getRowIndex().toString();
3826
+ this.actCell = sheetName + '!' + cellTxt;
3827
+ if (calcFamily.sheetNameToParentObject !== null && calcFamily.sheetNameToParentObject.size > 0) {
3828
+ var token = calcFamily.parentObjectToToken.get(pgrid);
3829
+ cellTxt = token + cellTxt;
3830
+ }
3831
+ var argVal = changeArgs.getFormulaValue().toUpperCase();
3832
+ if (argVal.indexOf('=RAND()') > -1 || argVal.indexOf('=NOW()') > -1 || argVal.indexOf('NOW()') > -1 || argVal.indexOf('RAND()') > -1 || argVal.indexOf('=RANDBETWEEN(') > -1 ||
3833
+ argVal.indexOf('RANDBETWEEN(') > -1 || this.randomValues.has(cellTxt)) {
3834
+ var randStrVal = this.randCollection.toString();
3835
+ if (!this.randomValues.has(cellTxt)) {
3836
+ this.randomValues.set(cellTxt, changeArgs.getFormulaValue());
3837
+ this.randCollection.push(cellTxt);
3838
+ this.isRandomVal = true;
3839
+ }
3840
+ else if (this.randomValues.has(cellTxt)) {
3841
+ if (argVal.indexOf('=RAND()') > -1 || argVal.indexOf('=NOW()') > -1 || argVal.indexOf('NOW()') > -1 || argVal.indexOf('RAND()') > -1 || argVal.indexOf('=RANDBETWEEN(') > -1 ||
3842
+ argVal.indexOf('RANDBETWEEN(') > -1) {
3843
+ this.randomValues.set(cellTxt, changeArgs.getFormulaValue());
3844
+ }
3845
+ else if (changeArgs.getFormulaValue().toUpperCase() !== this.randomValues.get(cellTxt.toUpperCase())) {
3846
+ this.randomValues.delete(cellTxt);
3847
+ randStrVal = randStrVal.split(cellTxt + this.parseArgumentSeparator).join('').split(this.parseArgumentSeparator + cellTxt).join('').split(cellTxt).join('');
3848
+ this.randCollection = randStrVal.split(this.parseArgumentSeparator);
3849
+ }
3850
+ if (this.randomValues.size === 0 && this.randCollection.length) {
3851
+ this.isRandomVal = false;
3852
+ this.randomValues.clear();
3853
+ this.randCollection = [];
3854
+ }
3855
+ }
3856
+ }
3857
+ if (changeArgs.getFormulaValue() && changeArgs.getFormulaValue()[0] === this.getFormulaCharacter()) {
3858
+ this.cell = cellTxt;
3859
+ var formula = void 0;
3860
+ if (!isNullOrUndefined(isCompute)) {
3861
+ isCompute = isCalculate;
3862
+ }
3863
+ if (this.getFormulaInfoTable().has(cellTxt)) {
3864
+ formula = this.getFormulaInfoTable().get(cellTxt);
3865
+ if (changeArgs.getFormulaValue() !== formula.getFormulaText() || formula.getParsedFormula() == null) {
3866
+ formula.setFormulaText(changeArgs.getFormulaValue());
3867
+ if (this.getDependentFormulaCells().has(this.cell)) {
3868
+ this.clearFormulaDependentCells(this.cell);
3869
+ }
3870
+ try {
3871
+ formula.setParsedFormula(this.parser.parseFormula(changeArgs.getFormulaValue()));
3872
+ }
3873
+ catch (ex) {
3874
+ formula.setFormulaValue(ex);
3875
+ isCompute = false;
3876
+ }
3877
+ }
3878
+ else {
3879
+ this.parser.isError = false;
3880
+ }
3881
+ if (isCompute) {
3882
+ this.parser.isFormulaParsed = true;
3883
+ var cValue = this.calculateFormula(formula.getParsedFormula(), refresh);
3884
+ isComputedValueChanged = cValue !== formula.getFormulaValue() && (!this.parentObject.isEdit ||
3885
+ cValue !== this.formulaErrorStrings[FormulasErrorsStrings.CircularReference]);
3886
+ formula.setFormulaValue(cValue);
3887
+ }
3888
+ }
3889
+ else {
3890
+ formula = new FormulaInfo();
3891
+ formula.setFormulaText(changeArgs.getFormulaValue());
3892
+ if (!this.getDependentFormulaCells().has(cellTxt)) {
3893
+ this.getDependentFormulaCells().set(cellTxt, new Map());
3894
+ }
3895
+ this.getFormulaInfoTable().set(cellTxt, formula);
3896
+ try {
3897
+ formula.setParsedFormula(this.parser.parseFormula(changeArgs.getFormulaValue()));
3898
+ }
3899
+ catch (ex) {
3900
+ formula.setFormulaValue(ex);
3901
+ isCompute = false;
3902
+ }
3903
+ if (isCompute) {
3904
+ var cValue = this.calculateFormula(formula.getParsedFormula(), refresh);
3905
+ isComputedValueChanged = cValue !== this.formulaErrorStrings[FormulasErrorsStrings.CircularReference];
3906
+ formula.setFormulaValue(cValue);
3907
+ }
3908
+ }
3909
+ if (isCompute) {
3910
+ /* eslint-disable */
3911
+ if (this.parentObject.setValueRowCol === undefined) {
3912
+ this.setValueRowCol(this.getSheetID(pgrid) + 1, formula.getFormulaValue(), changeArgs.getRowIndex(), changeArgs.getColIndex());
3913
+ }
3914
+ else {
3915
+ this.parentObject.setValueRowCol(this.getSheetId(pgrid), formula.getFormulaValue(), changeArgs.getRowIndex(), changeArgs.getColIndex(), formula.getFormulaText(), isRandomFormula);
3916
+ }
3917
+ /* eslint-enable */
3918
+ }
3919
+ }
3920
+ else if (this.getFormulaInfoTable().has(cellTxt)) {
3921
+ this.getFormulaInfoTable().delete(cellTxt);
3922
+ if (this.getDependentFormulaCells().has(cellTxt)) {
3923
+ this.clearFormulaDependentCells(cellTxt);
3924
+ }
3925
+ }
3926
+ if (isCompute && isComputedValueChanged && this.getDependentCells().has(cellTxt) &&
3927
+ (this.parentObject.calculationMode === 'Automatic' ||
3928
+ !this.parentObject.isEdit ||
3929
+ refreshDependentCells) && this.getDependentCells().get(cellTxt).toString() !== cellTxt) {
3930
+ this.refreshDependentCells(cellTxt, undefined, undefined, randomFormulaRefreshing, isDelete, deletedRange, refreshDependentCells, action);
3931
+ }
3932
+ };
3933
+ /**
3934
+ * @hidden
3935
+ * @param {number} value - specify the value
3936
+ * @param {string | number} formulaValue - specify the formula value.
3937
+ * @param {number} row - specify the row
3938
+ * @param {number} col - specify the col.
3939
+ * @returns {void} - to set value row and column.
3940
+ */
3941
+ /**
3942
+ * Writes a computed value into standalone storage for the given sheet/row/column.
3943
+ *
3944
+ * @param {string | number | boolean | Object} value - Sheet id used to build the storage key.
3945
+ * @param {string | number | Object} formulaValue - Value to store.
3946
+ * @param {number} row - 1-based row index.
3947
+ * @param {number} col - 1-based column index.
3948
+ * @returns {void}
3949
+ */
3950
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3951
+ Calculate.prototype.setValueRowCol = function (value, formulaValue, row, col) {
3952
+ /* No Implementation */
3953
+ };
3954
+ Calculate.prototype.getSortedSheetNames = function () {
3955
+ var family = this.getSheetFamilyItem(this.grid);
3956
+ if (family != null && family.sheetNameToToken != null) {
3957
+ if (this.sortedSheetNames != null) {
3958
+ return this.sortedSheetNames;
3959
+ }
3960
+ var arr_1 = [];
3961
+ family.sheetNameToToken.forEach(function (_value, key) {
3962
+ arr_1.push(key);
3963
+ });
3964
+ arr_1.sort(function (a, b) { return b.length - a.length; });
3965
+ this.sortedSheetNames = arr_1;
3966
+ }
3967
+ return this.sortedSheetNames;
3968
+ };
3969
+ /**
3970
+ * Extracts an error line/label from an exception message when present.
3971
+ *
3972
+ * @param {string} error - Error object or message.
3973
+ * @returns {string} - Error line text, or an empty string.
3974
+ * @hidden
3975
+ */
3976
+ Calculate.prototype.getErrorLine = function (error) {
3977
+ /* eslint-disable-next-line */
3978
+ var errorStack = error.stack ? error.stack.split('\n')[1].split(':') : null;
3979
+ return errorStack ? errorStack[errorStack.length - 2] : null; // Getting row number of the error file.
3980
+ };
3981
+ /**
3982
+ * Allocates a new sheet family id for registering grids as sheets.
3983
+ *
3984
+ * @returns {string | number} - New family id.
3985
+ * @hidden
3986
+ */
3987
+ Calculate.prototype.createSheetFamilyID = function () {
3988
+ if (this.sheetFamilyID === Number.MAX_SAFE_INTEGER) {
3989
+ this.sheetFamilyID = Number.MIN_SAFE_INTEGER;
3990
+ }
3991
+ return this.sheetFamilyID++;
3992
+ };
3993
+ /**
3994
+ * Shared MIN / MAX evaluation over argument tokens.
3995
+ *
3996
+ * @param {string[]} args - Numeric argument tokens.
3997
+ * @param {string | number | Object} operation - `"min"` or `"max"`.
3998
+ * @returns {string} - Aggregate result string or error token.
3999
+ * @hidden
4000
+ */
4001
+ Calculate.prototype.computeMinMax = function (args, operation) {
4002
+ var result;
4003
+ var argVal;
4004
+ var isSubtotalFormula = false;
4005
+ if (args.length) {
4006
+ var lastArgument = args[args.length - 1];
4007
+ if (lastArgument === 'isSubtotal') {
4008
+ isSubtotalFormula = true;
4009
+ args.pop();
4010
+ }
4011
+ }
4012
+ if (isNullOrUndefined(args) || args.length === 0) {
4013
+ return this.formulaErrorStrings[FormulasErrorsStrings.WrongNumberArguments];
4014
+ }
4015
+ result = (operation === 'max') ? this.minValue : this.maxValue;
4016
+ for (var k = 0, len = args.length; k < len; k++) {
4017
+ if (args[k].split(this.tic).join('').trim() === '') {
4018
+ result = 0;
4019
+ }
4020
+ }
4021
+ var argArr = args;
4022
+ if (argArr.length > 255) {
4023
+ return this.getErrorStrings()[CommonErrors.Value];
4024
+ }
4025
+ for (var i = 0; i < argArr.length; i++) {
4026
+ if (argArr[i].indexOf(':') > -1 && this.isCellReference(argArr[i])) {
4027
+ var cellValue = this.getCellCollection(argArr[i]);
4028
+ for (var j = 0; j < cellValue.length; j++) {
4029
+ argVal = !isSubtotalFormula ? this.getValueFromArg(cellValue[j]) :
4030
+ this.getValueFromArg(cellValue[j], null, null, true);
4031
+ if (isSubtotalFormula && argVal.includes('SUBTOTAL(')) {
4032
+ continue;
4033
+ }
4034
+ var cellVal = this.parseFloat(argVal);
4035
+ if (argVal === '' || this.isNaN(this.parseFloat(cellVal)) || this.getErrorStrings().indexOf(argVal) > -1) {
4036
+ continue;
4037
+ }
4038
+ else {
4039
+ result = (operation === 'max') ? Math.max(result, cellVal) : Math.min(result, cellVal);
4040
+ }
4041
+ }
4042
+ }
4043
+ else {
4044
+ var val = !isSubtotalFormula ? this.getValueFromArg(argArr[i]) :
4045
+ this.getValueFromArg(argArr[i], null, null, true);
4046
+ if (isSubtotalFormula && val.includes('SUBTOTAL(')) {
4047
+ continue;
4048
+ }
4049
+ var cellVal = 0;
4050
+ var isCellRef = this.isCellReference(argArr[i]);
4051
+ var isEmptyCell = val === '' && isCellRef;
4052
+ var isStringCell = this.isNaN(this.parseFloat(val)) && isCellRef;
4053
+ var isBooleanCell = val === (this.trueValue || this.falseValue) && isCellRef;
4054
+ argArr[i] = argArr[i].startsWith('n') ? argArr[i].slice(1) : argArr[i];
4055
+ if (this.getErrorStrings().indexOf(val) > -1) {
4056
+ return val;
4057
+ }
4058
+ if (val === this.trueValue && argArr[i] === this.trueValue) {
4059
+ val = '1';
4060
+ }
4061
+ else if (val === this.falseValue && argArr[i] === this.falseValue) {
4062
+ val = '0';
4063
+ }
4064
+ else if (isEmptyCell || isStringCell || isBooleanCell) {
4065
+ continue;
4066
+ }
4067
+ if (val.indexOf('"') > -1) {
4068
+ val = val.split(this.tic).join('');
4069
+ }
4070
+ if (this.isNaN(this.parseFloat(val))) {
4071
+ return this.getErrorStrings()[CommonErrors.Value];
4072
+ }
4073
+ cellVal = this.parseFloat(val);
4074
+ result = operation === 'max' ? Math.max(result, cellVal) : Math.min(result, cellVal);
4075
+ }
4076
+ }
4077
+ if (result === this.minValue || result === this.maxValue) {
4078
+ result = 0;
4079
+ }
4080
+ return result.toString();
4081
+ };
4082
+ /**
4083
+ * Shared AVERAGE evaluation over argument tokens.
4084
+ *
4085
+ * @param {string[]} args - Numeric argument tokens.
4086
+ * @param {boolean} isSubtotalFormula - When `true`, applies SUBTOTAL visibility rules.
4087
+ * @returns {string} - Average as a string, or an error token.
4088
+ * @hidden
4089
+ */
4090
+ Calculate.prototype.calculateAvg = function (args, isSubtotalFormula) {
4091
+ var argArr = args;
4092
+ var cellColl = [];
4093
+ var cellVal;
4094
+ var value;
4095
+ var avgVal = 0;
4096
+ var countNum = 0;
4097
+ for (var k = 0; k < argArr.length; k++) {
4098
+ if (this.isCellReference(argArr[k])) {
4099
+ if (argArr[k].indexOf(':') > -1) {
4100
+ cellColl = this.getCellCollection(argArr[k]);
4101
+ for (var i = 0; i < cellColl.length; i++) {
4102
+ cellVal = !isSubtotalFormula ? this.getValueFromArg(cellColl[i]) :
4103
+ this.getValueFromArg(cellColl[i], null, null, true);
4104
+ if (isSubtotalFormula && cellVal.includes('SUBTOTAL(')) {
4105
+ continue;
4106
+ }
4107
+ if (this.getErrorStrings().indexOf(cellVal) > -1) {
4108
+ return cellVal;
4109
+ }
4110
+ else if (isNullOrUndefined(cellVal) || isNaN(this.parseFloat(cellVal)) || cellVal === '') {
4111
+ continue;
4112
+ }
4113
+ avgVal = avgVal + this.parseFloat(cellVal);
4114
+ countNum = countNum + 1;
4115
+ }
4116
+ }
4117
+ else {
4118
+ cellVal = !isSubtotalFormula ? this.getValueFromArg(argArr[k]) :
4119
+ this.getValueFromArg(argArr[k], null, null, true);
4120
+ if (isSubtotalFormula && cellVal.includes('SUBTOTAL(')) {
4121
+ continue;
4122
+ }
4123
+ if (this.getErrorStrings().indexOf(cellVal) > -1) {
4124
+ return cellVal;
4125
+ }
4126
+ else if (isNullOrUndefined(cellVal) || isNaN(this.parseFloat(cellVal)) || cellVal === '') {
4127
+ continue;
4128
+ }
4129
+ avgVal = avgVal + this.parseFloat(cellVal);
4130
+ countNum = countNum + 1;
4131
+ }
4132
+ }
4133
+ else {
4134
+ if (argArr[k].indexOf(this.tic) > -1) {
4135
+ if (isNaN(this.parseFloat(argArr[k].split(this.tic).join(''))) ||
4136
+ argArr[k].split(this.tic).join('').trim() === '') {
4137
+ return this.getErrorStrings()[CommonErrors.Value];
4138
+ }
4139
+ }
4140
+ if (argArr[k].length === 0 || args[k] === this.falseValue) {
4141
+ argArr[k] = '0';
4142
+ }
4143
+ if (args[k] === this.trueValue) {
4144
+ argArr[k] = '1';
4145
+ }
4146
+ value = this.getValueFromArg(argArr[k].split(this.tic).join(''));
4147
+ if (this.getErrorStrings().indexOf(value) > -1) {
4148
+ return value;
4149
+ }
4150
+ avgVal = avgVal + this.parseFloat(value);
4151
+ countNum = countNum + 1;
4152
+ }
4153
+ }
4154
+ if (countNum === 0) {
4155
+ return this.getErrorStrings()[CommonErrors.DivZero];
4156
+ }
4157
+ return (avgVal / countNum).toString();
4158
+ };
4159
+ /**
4160
+ * Registers a grid/model as a named sheet within a sheet family.
4161
+ *
4162
+ * @param {string} refName - Sheet reference name.
4163
+ * @param {Object} model - Grid / model object (or id string).
4164
+ * @param {string | number | Object} sheetFamilyID - Family id from {@link createSheetFamilyID}.
4165
+ * @returns {string} - Sheet token assigned to the model.
4166
+ */
4167
+ Calculate.prototype.registerGridAsSheet = function (refName, model, sheetFamilyID) {
4168
+ if (isNullOrUndefined(this.modelToSheetID)) {
4169
+ this.modelToSheetID = new Map();
4170
+ }
4171
+ if (isNullOrUndefined(this.modelToSheetID.get(model))) {
4172
+ this.modelToSheetID.set(model, sheetFamilyID);
4173
+ }
4174
+ var family = this.getSheetFamilyItem(model);
4175
+ family.isSheetMember = true;
4176
+ var tempRef = refName.toUpperCase();
4177
+ if (family.parentObjectToToken.size === 0) {
4178
+ family.parentObjectToToken = new Map();
4179
+ }
4180
+ if (family.sheetNameToParentObject.size === 0) {
4181
+ family.sheetNameToParentObject = new Map();
4182
+ }
4183
+ if (family.sheetNameToToken.size === 0) {
4184
+ family.sheetNameToToken = new Map();
4185
+ }
4186
+ if (family.tokenToParentObject.size === 0) {
4187
+ family.tokenToParentObject = new Map();
4188
+ }
4189
+ if (!isUndefined(family.sheetNameToParentObject.get(tempRef))) {
4190
+ var token = family.sheetNameToToken.get(tempRef);
4191
+ family.tokenToParentObject.set(token, model);
4192
+ family.parentObjectToToken.set(model, token);
4193
+ }
4194
+ else {
4195
+ var token = this.sheetToken + this.tokenCount.toString() + this.sheetToken;
4196
+ this.tokenCount++;
4197
+ family.tokenToParentObject.set(token, model);
4198
+ family.parentObjectToToken.set(model, token);
4199
+ family.sheetNameToToken.set(tempRef, token);
4200
+ family.sheetNameToParentObject.set(tempRef, model);
4201
+ }
4202
+ this.sortedSheetNames = null;
4203
+ return refName;
4204
+ };
4205
+ /**
4206
+ * Unregisters a sheet name (or all sheets) from a sheet family.
4207
+ *
4208
+ * @param {string} refName - Sheet reference name to remove.
4209
+ * @param {Object} model - Grid / model object associated with the sheet.
4210
+ * @param {Object} unRegisterAll - When `true`, removes all registered sheets for the model.
4211
+ * @returns {void}
4212
+ */
4213
+ Calculate.prototype.unregisterGridAsSheet = function (refName, model, unRegisterAll) {
4214
+ var _this = this;
4215
+ var modelArr = [model];
4216
+ if (unRegisterAll) {
4217
+ modelArr = [];
4218
+ if (!isNullOrUndefined(this.modelToSheetID)) {
4219
+ this.modelToSheetID.forEach(function (value, key) {
4220
+ modelArr.push(key);
4221
+ });
4222
+ }
4223
+ }
4224
+ modelArr.forEach(function (value) {
4225
+ var family = _this.getSheetFamilyItem(value);
4226
+ var refName1 = (unRegisterAll ? value : refName).toUpperCase();
4227
+ if (family.sheetNameToParentObject != null && family.sheetNameToParentObject.has(refName1)) {
4228
+ family.sheetNameToParentObject.delete(refName1);
4229
+ var token = family.sheetNameToToken.get(refName1);
4230
+ family.sheetNameToToken.delete(refName1);
4231
+ family.tokenToParentObject.delete(token);
4232
+ family.parentObjectToToken.delete(value);
4233
+ }
4234
+ if (_this.modelToSheetID && _this.modelToSheetID.has(value)) {
4235
+ _this.modelToSheetID.delete(value);
4236
+ }
4237
+ });
4238
+ this.sortedSheetNames = null;
4239
+ };
4240
+ /**
4241
+ * Parses and evaluates a formula expression in one call (always re-parses).
4242
+ *
4243
+ * @param {string} formula - Formula text to evaluate.
4244
+ * @param {boolean} isFromComputeExpression - Internal flag passed through to {@link computeFormula}.
4245
+ * @returns {string} - Computed value or error token.
4246
+ *
4247
+ * @example
4248
+ * ```ts
4249
+ * engine.computeExpression('=AVERAGE(1,2,3)'); // '2'
4250
+ * ```
4251
+ */
4252
+ Calculate.prototype.computeExpression = function (formula, isFromComputeExpression) {
4253
+ var parsedFormula = this.parser.parseFormula(formula);
4254
+ var calcValue = this.computeFormula(parsedFormula, isFromComputeExpression);
4255
+ return calcValue;
4256
+ };
4257
+ Calculate.prototype.isSheetMember = function () {
4258
+ var family = this.getSheetFamilyItem(this.grid);
4259
+ return isNullOrUndefined(family) ? false : family.isSheetMember;
4260
+ };
4261
+ /**
4262
+ * Releases engine state (stored values, named ranges, dependency graphs, sheet
4263
+ * families, volatile tracking, and library formulas).
4264
+ *
4265
+ * Call when the engine instance is no longer needed.
4266
+ *
4267
+ * @returns {void}
4268
+ */
4269
+ Calculate.prototype.destroy = function () {
4270
+ this.resetKeys();
4271
+ if (this.dependentCells) {
4272
+ this.dependentCells.clear();
4273
+ this.dependentCells = null;
4274
+ }
4275
+ if (this.dependentFormulaCells) {
4276
+ this.dependentFormulaCells.clear();
4277
+ this.dependentFormulaCells = null;
4278
+ }
4279
+ if (this.formulaInfoTable) {
4280
+ this.formulaInfoTable.clear();
4281
+ this.formulaInfoTable = null;
4282
+ }
4283
+ this.namedRanges.clear();
4284
+ this.randomValues.clear();
4285
+ this.randCollection = [];
4286
+ this.dependencyCollection = [];
4287
+ this.uniqueRange = [];
4288
+ this.sortRange = [];
4289
+ this.sortedSheetNames = null;
4290
+ this.evaluatingKeys.clear();
4291
+ if (this.sheetFamiliesList) {
4292
+ this.sheetFamiliesList.forEach(function (family) {
4293
+ if (family.sheetDependentFormulaCells) {
4294
+ family.sheetDependentFormulaCells.clear();
4295
+ }
4296
+ if (family.sheetFormulaInfotable) {
4297
+ family.sheetFormulaInfotable.clear();
4298
+ }
4299
+ if (family.tokenToParentObject) {
4300
+ family.tokenToParentObject.clear();
4301
+ }
4302
+ if (family.parentObjectToToken) {
4303
+ family.parentObjectToToken.clear();
4304
+ }
4305
+ if (family.sheetNameToParentObject) {
4306
+ family.sheetNameToParentObject.clear();
4307
+ }
4308
+ if (family.sheetNameToToken) {
4309
+ family.sheetNameToToken.clear();
4310
+ }
4311
+ });
4312
+ this.sheetFamiliesList.clear();
4313
+ this.sheetFamiliesList = null;
4314
+ }
4315
+ if (this.modelToSheetID) {
4316
+ this.modelToSheetID.clear();
4317
+ this.modelToSheetID = null;
4318
+ }
4319
+ this.defaultFamilyItem = null;
4320
+ this.lFormulas.clear();
4321
+ if (this.parser) {
4322
+ this.parser.destroy();
4323
+ }
4324
+ this.parentObject = null;
4325
+ this.grid = null;
4326
+ if (typeof this.destroy === 'function') {
4327
+ try {
4328
+ this.destroy();
4329
+ }
4330
+ catch (_e) {
4331
+ /* Base.destroy may require DOM; ignore in headless destroy */
4332
+ }
4333
+ }
4334
+ };
4335
+ /**
4336
+ * Recomputes volatile random formula cells tracked by the engine.
4337
+ *
4338
+ * @param {string} cellRef - Cell reference that triggered the refresh (removed from the random set when present).
4339
+ * @hidden
4340
+ * @returns {void}
4341
+ */
4342
+ Calculate.prototype.refreshRandValues = function (cellRef) {
4343
+ var rowIdx;
4344
+ var colIdx;
4345
+ var value;
4346
+ var tokenRef = '';
4347
+ var family;
4348
+ if (this.randomValues.has(cellRef)) {
4349
+ this.randomValues.delete(cellRef);
4350
+ var randIdx = this.randCollection.indexOf(cellRef);
4351
+ if (randIdx > -1) {
4352
+ this.randCollection.splice(randIdx, 1);
4353
+ }
4354
+ if (this.randomValues.size === 0 && !this.randCollection.length) {
4355
+ this.randomValues.clear();
4356
+ this.randCollection = [];
4357
+ }
4358
+ }
4359
+ for (var i = 0; i < this.randomValues.size; i++) {
4360
+ rowIdx = this.rowIndex(this.randCollection[i]);
4361
+ colIdx = this.colIndex(this.randCollection[i]);
4362
+ tokenRef = (parseFloat(this.getSheetToken(this.randCollection[i]).split(this.sheetToken).join('')) + 1).toString();
4363
+ family = this.getSheetFamilyItem(tokenRef);
4364
+ this.grid = family.sheetNameToParentObject.get(tokenRef);
4365
+ value = this.randomValues.get(this.randCollection[i]);
4366
+ value = this.computeFormula(value);
4367
+ if (this.parentObject.setValueRowCol === undefined) {
4368
+ this.setValueRowCol(this.getSheetID(this.grid) + 1, value, rowIdx, colIdx);
4369
+ }
4370
+ else {
4371
+ this.parentObject.setValueRowCol(this.getSheetId(this.grid), value, rowIdx, colIdx);
4372
+ }
4373
+ }
4374
+ };
4375
+ /**
4376
+ * Recalculates cells that depend on `cellRef` according to calculation mode and options.
4377
+ *
4378
+ * @hidden
4379
+ * @param {string} cellRef - Changed cell reference.
4380
+ * @param {string} uniqueCell - Optional UNIQUE spill context cell to skip.
4381
+ * @param {string} dependentCell - Accumulator of already-refreshed dependents (used for recursion).
4382
+ * @param {boolean} isRandomFormula - Whether refresh is for volatile random formulas.
4383
+ * @param {boolean} isDelete - Whether refresh follows a delete.
4384
+ * @param {string} deletedRange - Deleted range indexes.
4385
+ * @param {string | number | Object} refreshDependentCells - Forces dependent updates.
4386
+ * @param {string | number | Object} action - Optional action label (for example `"calculate"`).
4387
+ */
4388
+ Calculate.prototype.refreshDependentCells = function (cellRef, uniqueCell, dependentCell, isRandomFormula, isDelete, deletedRange, refreshDependentCells, action) {
4389
+ var _this = this;
4390
+ var refreshCells;
4391
+ if (!dependentCell) {
4392
+ refreshCells = true;
4393
+ dependentCell = [];
4394
+ }
4395
+ var family = this.getSheetFamilyItem(this.grid);
4396
+ try {
4397
+ var dependentCells = this.getDependentCells().get(cellRef);
4398
+ if (dependentCells && dependentCells.length !== 0 &&
4399
+ (this.parentObject.calculationMode === 'Automatic' ||
4400
+ refreshDependentCells || action === 'calculate')) {
4401
+ var i = void 0;
4402
+ for (i = 0; i < dependentCells.length; i++) {
4403
+ var dCell = dependentCells[i];
4404
+ if ((uniqueCell && dCell.indexOf(uniqueCell) > -1) || dCell === cellRef || dependentCell.indexOf(dCell) > -1) {
4405
+ continue;
4406
+ }
4407
+ var token = this.getSheetToken(dCell);
4408
+ var sheets = this.parentObject.sheets;
4409
+ var sheetIdx = this.parentObject.activeSheetIndex;
4410
+ if (token.length) {
4411
+ this.grid = family.tokenToParentObject.get(token);
4412
+ var sheetId = Number(this.grid);
4413
+ var sheetName = '';
4414
+ if (!this.isNaN(sheetId) && sheets) {
4415
+ for (var i_1 = 0; i_1 < sheets.length; i_1++) {
4416
+ if (sheets[i_1].id === sheetId) {
4417
+ sheetName = sheets[i_1].name;
4418
+ sheetIdx = i_1;
4419
+ }
4420
+ }
4421
+ }
4422
+ this.actCell = sheetName + '!' + dCell.split(token)[1];
4423
+ }
4424
+ else {
4425
+ this.actCell = dCell.split(token)[1];
4426
+ }
4427
+ try {
4428
+ var calculateFormula = function (cell, formulaInfo) {
4429
+ if (formulaInfo) {
4430
+ _this.cell = cell;
4431
+ _this.parser.isFormulaParsed = true;
4432
+ formulaInfo.setFormulaValue(_this.calculateFormula(formulaInfo.getParsedFormula(), true));
4433
+ }
4434
+ };
4435
+ var rowIdx = this.rowIndex(dCell);
4436
+ var colIdx = this.colIndex(dCell);
4437
+ var formulaInfo = this.getFormulaInfoTable().get(dCell);
4438
+ if (this.parentObject.setValueRowCol === undefined) {
4439
+ calculateFormula(dCell, formulaInfo);
4440
+ this.setValueRowCol(this.getSheetID(this.grid) + 1, formulaInfo.getFormulaValue(), rowIdx, colIdx);
4441
+ }
4442
+ else {
4443
+ var cell = sheets && sheets[sheetIdx].rows &&
4444
+ sheets[sheetIdx].rows[rowIdx - 1] && sheets[sheetIdx].rows[rowIdx - 1].cells &&
4445
+ sheets[sheetIdx].rows[rowIdx - 1].cells[colIdx - 1];
4446
+ var val = void 0;
4447
+ if (cell && cell.formula && cell.formula.toLowerCase().includes('unique')) {
4448
+ if (!this.uniqueCells || this.uniqueCells.indexOf(dCell) === -1) {
4449
+ if (!this.uniqueCells) {
4450
+ this.uniqueCells = [];
4451
+ }
4452
+ this.uniqueCells.push(dCell);
4453
+ calculateFormula(dCell, formulaInfo);
4454
+ val = formulaInfo.getFormulaValue();
4455
+ this.uniqueCells.splice(this.uniqueCells.indexOf(dCell), 1);
4456
+ if (!this.uniqueCells.length) {
4457
+ this.uniqueCells = null;
4458
+ }
4459
+ }
4460
+ else {
4461
+ continue;
4462
+ }
4463
+ }
4464
+ else if (cell && cell.formula && cell.formula.toLowerCase().includes('sort')) {
4465
+ if (!this.sortCells || this.sortCells.indexOf(dCell) === -1) {
4466
+ if (!this.sortCells) {
4467
+ this.sortCells = [];
4468
+ }
4469
+ this.sortCells.push(dCell);
4470
+ calculateFormula(dCell, formulaInfo);
4471
+ val = formulaInfo.getFormulaValue();
4472
+ this.sortCells.splice(this.sortCells.indexOf(dCell), 1);
4473
+ if (!this.sortCells.length) {
4474
+ this.sortCells = null;
4475
+ }
4476
+ }
4477
+ else {
4478
+ continue;
4479
+ }
4480
+ }
4481
+ else {
4482
+ if (dependentCell.indexOf(dCell) === -1) {
4483
+ dependentCell.push(dCell);
4484
+ }
4485
+ val = null;
4486
+ }
4487
+ this.parentObject.setValueRowCol(this.getSheetId(this.grid), val, rowIdx, colIdx, formulaInfo.getFormulaText());
4488
+ }
4489
+ this.refreshDependentCells(dCell, null, dependentCell, null, isDelete);
4490
+ }
4491
+ catch (ex) {
4492
+ continue;
4493
+ }
4494
+ }
4495
+ }
4496
+ if (refreshCells) {
4497
+ if (!isDelete && deletedRange && deletedRange.length === 4) {
4498
+ var token = this.getSheetToken(cellRef);
4499
+ var deletedCell = [];
4500
+ for (var sRIdx = deletedRange[0], eRIdx = deletedRange[2]; sRIdx <= eRIdx; sRIdx++) {
4501
+ for (var sCIdx = deletedRange[1], eCIdx = deletedRange[3]; sCIdx <= eCIdx; sCIdx++) {
4502
+ if (sRIdx === eRIdx && sCIdx === eCIdx) {
4503
+ break;
4504
+ }
4505
+ var cell = token + getCellAddress(sRIdx, sCIdx);
4506
+ this.refreshDependentCells(cell, null, dependentCell, null, isDelete);
4507
+ deletedCell.push(cell);
4508
+ }
4509
+ }
4510
+ var ranges_1 = new Set(deletedCell);
4511
+ if (dependentCell) {
4512
+ dependentCell = dependentCell.filter(function (item) { return !ranges_1.has(item); });
4513
+ }
4514
+ }
4515
+ var sheets_1 = this.parentObject.sheets;
4516
+ if (!sheets_1) {
4517
+ dependentCell = [];
4518
+ }
4519
+ dependentCell.forEach(function (cell) {
4520
+ var sheetIdx;
4521
+ var sheetId = _this.getSheetId(family.tokenToParentObject.get(_this.getSheetToken(cell)));
4522
+ for (var idx = 0; idx < sheets_1.length; idx++) {
4523
+ if (sheets_1[idx].id === sheetId) {
4524
+ sheetIdx = idx;
4525
+ break;
4526
+ }
4527
+ }
4528
+ var rowIdx = _this.rowIndex(cell) - 1;
4529
+ var colIdx = _this.colIndex(cell) - 1;
4530
+ var cellObj = sheets_1[sheetIdx].rows[rowIdx] &&
4531
+ sheets_1[sheetIdx].rows[rowIdx].cells[colIdx];
4532
+ if (cellObj) {
4533
+ _this.parentObject.notify('calculateFormula', { cell: cellObj, rowIdx: rowIdx, colIdx: colIdx, sheetIndex: sheetIdx, isDependentRefresh: true, isRandomFormula: isRandomFormula, action: action });
4534
+ }
4535
+ });
4536
+ }
4537
+ }
4538
+ finally {
4539
+ if (this.getDependentCells().has(cellRef)) {
4540
+ this.grid = family.tokenToParentObject.get(this.getSheetToken(cellRef));
4541
+ }
4542
+ }
4543
+ };
4544
+ __decorate([
4545
+ Event()
4546
+ ], Calculate.prototype, "onFailure", void 0);
4547
+ Calculate = __decorate([
4548
+ NotifyPropertyChanges
4549
+ ], Calculate);
4550
+ return Calculate;
4551
+ }(Base));
4552
+ export { Calculate };
4553
+ /**
4554
+ * Formula parse/evaluation error raised by the Calculate engine.
4555
+ *
4556
+ * @hidden
4557
+ */
4558
+ var FormulaError = /** @class */ (function () {
4559
+ /**
4560
+ * @param {string | number | Object} errorMessage - Error description.
4561
+ * @param {string} formulaAutoCorrection - Whether formula auto-correction is available.
4562
+ */
4563
+ function FormulaError(errorMessage, formulaAutoCorrection) {
4564
+ /** When `true`, the parser suggests an auto-corrected formula. */
4565
+ this.formulaCorrection = false;
4566
+ this.message = errorMessage;
4567
+ this.formulaCorrection = formulaAutoCorrection;
4568
+ }
4569
+ return FormulaError;
4570
+ }());
4571
+ export { FormulaError };
4572
+ /**
4573
+ * Cached formula text, parsed form, and computed value for a cell.
4574
+ *
4575
+ * @hidden
4576
+ */
4577
+ var FormulaInfo = /** @class */ (function () {
4578
+ function FormulaInfo() {
4579
+ /** Calculation generation id for cache invalidation. */
4580
+ this.calcID = Number.MIN_VALUE + 1;
4581
+ this.calcID1 = Number.MIN_VALUE + 1;
4582
+ }
4583
+ /**
4584
+ * Returns the stored formula text for this cell.
4585
+ *
4586
+ * @returns {string} - Formula text, or `undefined` when unset.
4587
+ */
4588
+ FormulaInfo.prototype.getFormulaText = function () {
4589
+ return this.formulaText;
4590
+ };
4591
+ /**
4592
+ * Sets the formula text for this cell.
4593
+ *
4594
+ * @param {string | number | boolean | Object} value - Formula text (typically including leading `=`).
4595
+ * @returns {void}
4596
+ */
4597
+ FormulaInfo.prototype.setFormulaText = function (value) {
4598
+ this.formulaText = value;
4599
+ };
4600
+ /**
4601
+ * Returns the last computed value for this cell.
4602
+ *
4603
+ * @returns {string} - Computed value or error token.
4604
+ */
4605
+ FormulaInfo.prototype.getFormulaValue = function () {
4606
+ return this.formulaValue;
4607
+ };
4608
+ /**
4609
+ * Sets the computed value for this cell.
4610
+ *
4611
+ * @param {string | number | boolean | Object} value - Computed result.
4612
+ * @returns {void}
4613
+ */
4614
+ FormulaInfo.prototype.setFormulaValue = function (value) {
4615
+ this.formulaValue = value;
4616
+ };
4617
+ /**
4618
+ * Returns the parser token string for this cell's formula.
4619
+ *
4620
+ * @returns {string | number} - Parsed formula tokens.
4621
+ */
4622
+ FormulaInfo.prototype.getParsedFormula = function () {
4623
+ return this.parsedFormula;
4624
+ };
4625
+ /**
4626
+ * Sets the parser token string for this cell's formula.
4627
+ *
4628
+ * @param {string | number | boolean | Object} value - Parsed formula tokens from {@link Parser.parseFormula}.
4629
+ * @returns {void}
4630
+ */
4631
+ FormulaInfo.prototype.setParsedFormula = function (value) {
4632
+ this.parsedFormula = value;
4633
+ };
4634
+ return FormulaInfo;
4635
+ }());
4636
+ export { FormulaInfo };
4637
+ /**
4638
+ * Per-family sheet registration and dependency tables used when multiple grids share an engine.
4639
+ *
4640
+ * @hidden
4641
+ */
4642
+ var CalcSheetFamilyItem = /** @class */ (function () {
4643
+ function CalcSheetFamilyItem() {
4644
+ /** Whether this family participates in multi-sheet evaluation. */
4645
+ this.isSheetMember = false;
4646
+ /** Maps parent grid objects to their sheet tokens. */
4647
+ this.parentObjectToToken = new Map();
4648
+ /** Formula dependency map scoped to this sheet family. */
4649
+ this.sheetDependentFormulaCells = new Map();
4650
+ /** Maps sheet names to parent grid objects. */
4651
+ this.sheetNameToParentObject = new Map();
4652
+ /** Maps sheet names to sheet tokens. */
4653
+ this.sheetNameToToken = new Map();
4654
+ /** Maps sheet tokens to parent grid objects. */
4655
+ this.tokenToParentObject = new Map();
4656
+ /** Formula info table scoped to this sheet family. */
4657
+ this.sheetFormulaInfotable = new Map();
4658
+ }
4659
+ return CalcSheetFamilyItem;
4660
+ }());
4661
+ export { CalcSheetFamilyItem };
4662
+ /**
4663
+ * Converts a 1-based column index to Excel column letters.
4664
+ *
4665
+ * @param {number} col - 1-based column index.
4666
+ * @returns {string | number} - Column letters (for example `1` → `"A"`).
4667
+ * @hidden
4668
+ */
4669
+ export function getAlphalabel(col) {
4670
+ var cols = [];
4671
+ var n = 0;
4672
+ var charText = 'A';
4673
+ while (col > 0 && n < 9) {
4674
+ col--;
4675
+ var aCharNo = charText.charCodeAt(0);
4676
+ cols[n] = String.fromCharCode(col % 26 + aCharNo);
4677
+ col = parseInt((col / 26).toString(), 10);
4678
+ n++;
4679
+ }
4680
+ var chs = [];
4681
+ for (var i = 0; i < n; i++) {
4682
+ chs[n - i - 1] = cols[i];
4683
+ }
4684
+ return chs.join('');
4685
+ }
4686
+ /**
4687
+ * Arguments describing a cell value/formula change for {@link Calculate.valueChanged}.
4688
+ *
4689
+ * @hidden
4690
+ */
4691
+ var ValueChangedArgs = /** @class */ (function () {
4692
+ /**
4693
+ * @param {number} row - 1-based row index.
4694
+ * @param {number} col - 1-based column index.
4695
+ * @param {string | number | boolean | Object} value - Formula text or literal value.
4696
+ */
4697
+ function ValueChangedArgs(row, col, value) {
4698
+ this.row = row;
4699
+ this.col = col;
4700
+ this.value = value;
4701
+ this.getRowIndex = function () {
4702
+ return row;
4703
+ };
4704
+ this.setRowIndex = function (value) {
4705
+ row = value;
4706
+ };
4707
+ this.getColIndex = function () {
4708
+ return col;
4709
+ };
4710
+ this.setColIndex = function (value) {
4711
+ col = value;
4712
+ };
4713
+ this.getFormulaValue = function () {
4714
+ return value;
4715
+ };
4716
+ return this;
4717
+ }
4718
+ return ValueChangedArgs;
4719
+ }());
4720
+ export { ValueChangedArgs };