@lofcz/tinysheet-formula-parser 0.2.13 → 1.0.2
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.
- package/dist/index.d.ts +46 -0
- package/dist/index.js +934 -0
- package/package.json +19 -41
- package/es/error.js +0 -45
- package/es/evaluate-by-operator/evaluate-by-operator.js +0 -70
- package/es/evaluate-by-operator/operator/add.js +0 -16
- package/es/evaluate-by-operator/operator/ampersand.js +0 -10
- package/es/evaluate-by-operator/operator/divide.js +0 -21
- package/es/evaluate-by-operator/operator/equal.js +0 -5
- package/es/evaluate-by-operator/operator/formula-function.js +0 -40
- package/es/evaluate-by-operator/operator/greater-than-or-equal.js +0 -5
- package/es/evaluate-by-operator/operator/greater-than.js +0 -5
- package/es/evaluate-by-operator/operator/less-than-or-equal.js +0 -5
- package/es/evaluate-by-operator/operator/less-than.js +0 -5
- package/es/evaluate-by-operator/operator/minus.js +0 -16
- package/es/evaluate-by-operator/operator/multiply.js +0 -16
- package/es/evaluate-by-operator/operator/not-equal.js +0 -5
- package/es/evaluate-by-operator/operator/power.js +0 -11
- package/es/grammar-parser/grammar-parser.jison +0 -230
- package/es/grammar-parser/grammar-parser.js +0 -1522
- package/es/helper/cell.js +0 -117
- package/es/helper/number.js +0 -25
- package/es/helper/string.js +0 -13
- package/es/index.js +0 -5
- package/es/parser.js +0 -306
- package/es/supported-formulas.js +0 -3
- package/lib/error.js +0 -53
- package/lib/evaluate-by-operator/evaluate-by-operator.js +0 -77
- package/lib/evaluate-by-operator/operator/add.js +0 -23
- package/lib/evaluate-by-operator/operator/ampersand.js +0 -17
- package/lib/evaluate-by-operator/operator/divide.js +0 -28
- package/lib/evaluate-by-operator/operator/equal.js +0 -12
- package/lib/evaluate-by-operator/operator/formula-function.js +0 -50
- package/lib/evaluate-by-operator/operator/greater-than-or-equal.js +0 -12
- package/lib/evaluate-by-operator/operator/greater-than.js +0 -12
- package/lib/evaluate-by-operator/operator/less-than-or-equal.js +0 -12
- package/lib/evaluate-by-operator/operator/less-than.js +0 -12
- package/lib/evaluate-by-operator/operator/minus.js +0 -23
- package/lib/evaluate-by-operator/operator/multiply.js +0 -23
- package/lib/evaluate-by-operator/operator/not-equal.js +0 -12
- package/lib/evaluate-by-operator/operator/power.js +0 -18
- package/lib/grammar-parser/grammar-parser.jison +0 -230
- package/lib/grammar-parser/grammar-parser.js +0 -1528
- package/lib/helper/cell.js +0 -128
- package/lib/helper/number.js +0 -32
- package/lib/helper/string.js +0 -19
- package/lib/index.js +0 -114
- package/lib/parser.js +0 -313
- package/lib/supported-formulas.js +0 -11
package/dist/index.js
ADDED
|
@@ -0,0 +1,934 @@
|
|
|
1
|
+
import Emitter from "tiny-emitter";
|
|
2
|
+
import * as formulajsNs from "@formulajs/formulajs";
|
|
3
|
+
import { EmbeddedActionsParser, Lexer, createToken } from "chevrotain";
|
|
4
|
+
//#region packages/formula-parser/src/helper/number.js
|
|
5
|
+
/**
|
|
6
|
+
* Convert value into number.
|
|
7
|
+
*
|
|
8
|
+
* @param {String|Number} number
|
|
9
|
+
* @returns {*}
|
|
10
|
+
*/
|
|
11
|
+
function toNumber(number) {
|
|
12
|
+
let result;
|
|
13
|
+
if (typeof number === "number") result = number;
|
|
14
|
+
else if (typeof number === "string") result = number.indexOf(".") > -1 ? parseFloat(number) : parseInt(number, 10);
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Invert provided number.
|
|
19
|
+
*
|
|
20
|
+
* @param {Number} number
|
|
21
|
+
* @returns {Number} Returns inverted number.
|
|
22
|
+
*/
|
|
23
|
+
function invertNumber(number) {
|
|
24
|
+
return -1 * toNumber(number);
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region packages/formula-parser/src/error.js
|
|
28
|
+
const ERROR = "ERROR";
|
|
29
|
+
const ERROR_DIV_ZERO = "DIV/0";
|
|
30
|
+
const ERROR_NAME = "NAME";
|
|
31
|
+
const ERROR_NOT_AVAILABLE = "N/A";
|
|
32
|
+
const ERROR_NULL = "NULL";
|
|
33
|
+
const ERROR_NUM = "NUM";
|
|
34
|
+
const ERROR_REF = "REF";
|
|
35
|
+
const ERROR_VALUE = "VALUE";
|
|
36
|
+
const errors = {
|
|
37
|
+
[ERROR]: "#ERROR!",
|
|
38
|
+
[ERROR_DIV_ZERO]: "#DIV/0!",
|
|
39
|
+
[ERROR_NAME]: "#NAME?",
|
|
40
|
+
["N/A"]: "#N/A",
|
|
41
|
+
[ERROR_NULL]: "#NULL!",
|
|
42
|
+
["NUM"]: "#NUM!",
|
|
43
|
+
["REF"]: "#REF!",
|
|
44
|
+
[ERROR_VALUE]: "#VALUE!"
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Return error type based on provided error id.
|
|
48
|
+
*
|
|
49
|
+
* @param {String} type Error type.
|
|
50
|
+
* @returns {String|null} Returns error id.
|
|
51
|
+
*/
|
|
52
|
+
function error(type) {
|
|
53
|
+
let result;
|
|
54
|
+
type = (type + "").replace(/#|!|\?/g, "");
|
|
55
|
+
if (errors[type]) result = errors[type];
|
|
56
|
+
return result ? result : null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Check if error type is strict valid with knows errors.
|
|
60
|
+
*
|
|
61
|
+
* @param {String} Error type.
|
|
62
|
+
* @return {Boolean}
|
|
63
|
+
*/
|
|
64
|
+
function isValidStrict(type) {
|
|
65
|
+
let valid = false;
|
|
66
|
+
for (const i in errors) if (Object.prototype.hasOwnProperty.call(errors, i) && errors[i] === type) {
|
|
67
|
+
valid = true;
|
|
68
|
+
break;
|
|
69
|
+
}
|
|
70
|
+
return valid;
|
|
71
|
+
}
|
|
72
|
+
function func$12(first, ...rest) {
|
|
73
|
+
const result = rest.reduce((acc, value) => acc + toNumber(value || 0), toNumber(first || 0));
|
|
74
|
+
if (isNaN(result)) throw Error(ERROR_VALUE);
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
func$12.SYMBOL = "+";
|
|
78
|
+
function func$11(...params) {
|
|
79
|
+
return params.reduce((acc, value) => acc + value.toString(), "");
|
|
80
|
+
}
|
|
81
|
+
func$11.SYMBOL = "&";
|
|
82
|
+
function func$10(first, ...rest) {
|
|
83
|
+
const result = rest.reduce((acc, value) => acc / toNumber(value), toNumber(first));
|
|
84
|
+
if (result === Infinity) throw Error(ERROR_DIV_ZERO);
|
|
85
|
+
if (isNaN(result)) throw Error(ERROR_VALUE);
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
func$10.SYMBOL = "/";
|
|
89
|
+
function func$9(exp1, exp2) {
|
|
90
|
+
return exp1 === exp2;
|
|
91
|
+
}
|
|
92
|
+
func$9.SYMBOL = "=";
|
|
93
|
+
//#endregion
|
|
94
|
+
//#region packages/formula-parser/src/formulajs.js
|
|
95
|
+
function functionKeyCount(obj) {
|
|
96
|
+
if (!obj || typeof obj !== "object") return 0;
|
|
97
|
+
return Object.keys(obj).filter((key) => typeof obj[key] === "function").length;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Vitest/Vite CJS interop puts formulas on `.default` (enumerable).
|
|
101
|
+
* Bun flattens them onto the namespace; `.default` is a smaller legacy map.
|
|
102
|
+
* Prefer whichever object exposes more formula functions.
|
|
103
|
+
*/
|
|
104
|
+
const formulajs = functionKeyCount(formulajsNs.default) > functionKeyCount(formulajsNs) ? formulajsNs.default : formulajsNs;
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region packages/formula-parser/src/supported-formulas.js
|
|
107
|
+
/**
|
|
108
|
+
* Collect formula call names, including Excel-style dotted paths
|
|
109
|
+
* (RANK.EQ, BINOM.DIST.RANGE, T.DIST.2T, …).
|
|
110
|
+
*
|
|
111
|
+
* Uses a path stack (not a global visited set) so the same formulajs
|
|
112
|
+
* function object can contribute aliases under multiple Excel names
|
|
113
|
+
* (e.g. CHIDIST.RT and CHISQ.DIST.RT).
|
|
114
|
+
*/
|
|
115
|
+
function collectSupportedFormulas(lib, prefix = "", names = /* @__PURE__ */ new Set(), stack = /* @__PURE__ */ new Set()) {
|
|
116
|
+
if (!lib || typeof lib !== "object" && typeof lib !== "function") return names;
|
|
117
|
+
if (stack.has(lib)) return names;
|
|
118
|
+
stack.add(lib);
|
|
119
|
+
for (const key of Object.keys(lib)) {
|
|
120
|
+
const value = lib[key];
|
|
121
|
+
const name = prefix ? `${prefix}.${key}` : key;
|
|
122
|
+
if (typeof value === "function") {
|
|
123
|
+
names.add(name);
|
|
124
|
+
collectSupportedFormulas(value, name, names, stack);
|
|
125
|
+
} else if (value && typeof value === "object") collectSupportedFormulas(value, name, names, stack);
|
|
126
|
+
}
|
|
127
|
+
stack.delete(lib);
|
|
128
|
+
return names;
|
|
129
|
+
}
|
|
130
|
+
const SUPPORTED_FORMULAS = [...collectSupportedFormulas(formulajs)];
|
|
131
|
+
//#endregion
|
|
132
|
+
//#region packages/formula-parser/src/evaluate-by-operator/operator/formula-function.js
|
|
133
|
+
const SYMBOL$8 = SUPPORTED_FORMULAS;
|
|
134
|
+
function func$8(symbol) {
|
|
135
|
+
return function __formulaFunction(...params) {
|
|
136
|
+
symbol = symbol.toUpperCase();
|
|
137
|
+
const symbolParts = symbol.split(".");
|
|
138
|
+
let foundFormula = false;
|
|
139
|
+
let result;
|
|
140
|
+
if (symbolParts.length === 1) {
|
|
141
|
+
if (formulajs[symbolParts[0]]) {
|
|
142
|
+
foundFormula = true;
|
|
143
|
+
result = formulajs[symbolParts[0]](...params);
|
|
144
|
+
}
|
|
145
|
+
} else {
|
|
146
|
+
const length = symbolParts.length;
|
|
147
|
+
let index = 0;
|
|
148
|
+
let nestedFormula = formulajs;
|
|
149
|
+
while (index < length) {
|
|
150
|
+
nestedFormula = nestedFormula[symbolParts[index]];
|
|
151
|
+
index++;
|
|
152
|
+
if (!nestedFormula) {
|
|
153
|
+
nestedFormula = null;
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
if (nestedFormula) {
|
|
158
|
+
foundFormula = true;
|
|
159
|
+
result = nestedFormula(...params);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
if (!foundFormula) throw Error(ERROR_NAME);
|
|
163
|
+
if (result instanceof Error) throw result;
|
|
164
|
+
return result;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
func$8.isFactory = true;
|
|
168
|
+
func$8.SYMBOL = SYMBOL$8;
|
|
169
|
+
function func$7(exp1, exp2) {
|
|
170
|
+
return exp1 > exp2;
|
|
171
|
+
}
|
|
172
|
+
func$7.SYMBOL = ">";
|
|
173
|
+
function func$6(exp1, exp2) {
|
|
174
|
+
return exp1 >= exp2;
|
|
175
|
+
}
|
|
176
|
+
func$6.SYMBOL = ">=";
|
|
177
|
+
function func$5(exp1, exp2) {
|
|
178
|
+
return exp1 < exp2;
|
|
179
|
+
}
|
|
180
|
+
func$5.SYMBOL = "<";
|
|
181
|
+
function func$4(exp1, exp2) {
|
|
182
|
+
return exp1 <= exp2;
|
|
183
|
+
}
|
|
184
|
+
func$4.SYMBOL = "<=";
|
|
185
|
+
function func$3(first, ...rest) {
|
|
186
|
+
const result = rest.reduce((acc, value) => acc - toNumber(value), toNumber(first));
|
|
187
|
+
if (isNaN(result)) throw Error(ERROR_VALUE);
|
|
188
|
+
return result;
|
|
189
|
+
}
|
|
190
|
+
func$3.SYMBOL = "-";
|
|
191
|
+
function func$2(first, ...rest) {
|
|
192
|
+
const result = rest.reduce((acc, value) => acc * toNumber(value), toNumber(first));
|
|
193
|
+
if (isNaN(result)) throw Error(ERROR_VALUE);
|
|
194
|
+
return result;
|
|
195
|
+
}
|
|
196
|
+
func$2.SYMBOL = "*";
|
|
197
|
+
function func$1(exp1, exp2) {
|
|
198
|
+
return exp1 !== exp2;
|
|
199
|
+
}
|
|
200
|
+
func$1.SYMBOL = "<>";
|
|
201
|
+
function func(exp1, exp2) {
|
|
202
|
+
const result = Math.pow(toNumber(exp1), toNumber(exp2));
|
|
203
|
+
if (isNaN(result)) throw Error(ERROR_VALUE);
|
|
204
|
+
return result;
|
|
205
|
+
}
|
|
206
|
+
func.SYMBOL = "^";
|
|
207
|
+
//#endregion
|
|
208
|
+
//#region packages/formula-parser/src/evaluate-by-operator/evaluate-by-operator.js
|
|
209
|
+
const availableOperators = Object.create(null);
|
|
210
|
+
/**
|
|
211
|
+
* Evaluate values by operator id.git
|
|
212
|
+
*
|
|
213
|
+
* @param {String} operator Operator id.
|
|
214
|
+
* @param {Array} [params=[]] Arguments to evaluate.
|
|
215
|
+
* @returns {*}
|
|
216
|
+
*/
|
|
217
|
+
function evaluateByOperator(operator, params = []) {
|
|
218
|
+
operator = operator.toUpperCase();
|
|
219
|
+
if (!availableOperators[operator]) throw Error(ERROR_NAME);
|
|
220
|
+
return availableOperators[operator](...params);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Register operator.
|
|
224
|
+
*
|
|
225
|
+
* @param {String|Array} symbol Symbol to register.
|
|
226
|
+
* @param {Function} func Logic to register for this symbol.
|
|
227
|
+
*/
|
|
228
|
+
function registerOperation(symbol, func) {
|
|
229
|
+
if (!Array.isArray(symbol)) symbol = [symbol.toUpperCase()];
|
|
230
|
+
symbol.forEach((s) => {
|
|
231
|
+
if (func.isFactory) availableOperators[s] = func(s);
|
|
232
|
+
else availableOperators[s] = func;
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
registerOperation(func$12.SYMBOL, func$12);
|
|
236
|
+
registerOperation(func$11.SYMBOL, func$11);
|
|
237
|
+
registerOperation(func$10.SYMBOL, func$10);
|
|
238
|
+
registerOperation(func$9.SYMBOL, func$9);
|
|
239
|
+
registerOperation(func.SYMBOL, func);
|
|
240
|
+
registerOperation(func$8.SYMBOL, func$8);
|
|
241
|
+
registerOperation(func$7.SYMBOL, func$7);
|
|
242
|
+
registerOperation(func$6.SYMBOL, func$6);
|
|
243
|
+
registerOperation(func$5.SYMBOL, func$5);
|
|
244
|
+
registerOperation(func$4.SYMBOL, func$4);
|
|
245
|
+
registerOperation(func$2.SYMBOL, func$2);
|
|
246
|
+
registerOperation(func$1.SYMBOL, func$1);
|
|
247
|
+
registerOperation(func$3.SYMBOL, func$3);
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region packages/formula-parser/src/grammar-parser/grammar-parser.js
|
|
250
|
+
const sheetNameRegexp = `(?:[A-Za-z0-9_À-ʯ]+|'(?:(?!').|'')*')!`;
|
|
251
|
+
const WhiteSpace = createToken({
|
|
252
|
+
name: "WhiteSpace",
|
|
253
|
+
pattern: /\s+/,
|
|
254
|
+
group: Lexer.SKIPPED
|
|
255
|
+
});
|
|
256
|
+
const StringLiteral = createToken({
|
|
257
|
+
name: "StringLiteral",
|
|
258
|
+
pattern: /"(?:\\["]|[^"])*"|'(?:\\[']|[^'])*'/
|
|
259
|
+
});
|
|
260
|
+
const ErrorLiteral = createToken({
|
|
261
|
+
name: "ErrorLiteral",
|
|
262
|
+
pattern: /#[A-Z0-9/]+[!?]?/
|
|
263
|
+
});
|
|
264
|
+
const FunctionName = createToken({
|
|
265
|
+
name: "FunctionName",
|
|
266
|
+
pattern: /[A-Za-z][A-Za-z0-9_.]*(?=\()/
|
|
267
|
+
});
|
|
268
|
+
const AbsoluteCell = createToken({
|
|
269
|
+
name: "AbsoluteCell",
|
|
270
|
+
pattern: new RegExp(`(?:${sheetNameRegexp})?\\$[A-Za-z]+\\$[0-9]+`)
|
|
271
|
+
});
|
|
272
|
+
const MixedCell = createToken({
|
|
273
|
+
name: "MixedCell",
|
|
274
|
+
pattern: new RegExp(`(?:${sheetNameRegexp})?(?:\\$[A-Za-z]+[0-9]+|[A-Za-z]+\\$[0-9]+)`)
|
|
275
|
+
});
|
|
276
|
+
const RelativeCell = createToken({
|
|
277
|
+
name: "RelativeCell",
|
|
278
|
+
pattern: new RegExp(`(?:${sheetNameRegexp})?[A-Za-z]+[0-9]+`)
|
|
279
|
+
});
|
|
280
|
+
const ArrayLiteral = createToken({
|
|
281
|
+
name: "ArrayLiteral",
|
|
282
|
+
pattern: /\[[^\]]*]/
|
|
283
|
+
});
|
|
284
|
+
const NumberLiteral = createToken({
|
|
285
|
+
name: "NumberLiteral",
|
|
286
|
+
pattern: /(?:\d+\.?\d*|\.\d+)/
|
|
287
|
+
});
|
|
288
|
+
const Variable = createToken({
|
|
289
|
+
name: "Variable",
|
|
290
|
+
pattern: /[A-Za-z_][A-Za-z0-9_.]*/
|
|
291
|
+
});
|
|
292
|
+
const NotOp = createToken({
|
|
293
|
+
name: "NotOp",
|
|
294
|
+
pattern: /NOT/,
|
|
295
|
+
longer_alt: Variable
|
|
296
|
+
});
|
|
297
|
+
const OpNe = createToken({
|
|
298
|
+
name: "OpNe",
|
|
299
|
+
pattern: /<>/
|
|
300
|
+
});
|
|
301
|
+
const OpLe = createToken({
|
|
302
|
+
name: "OpLe",
|
|
303
|
+
pattern: /<=/
|
|
304
|
+
});
|
|
305
|
+
const OpGe = createToken({
|
|
306
|
+
name: "OpGe",
|
|
307
|
+
pattern: />=/
|
|
308
|
+
});
|
|
309
|
+
const OpEq = createToken({
|
|
310
|
+
name: "OpEq",
|
|
311
|
+
pattern: /=/
|
|
312
|
+
});
|
|
313
|
+
const OpLt = createToken({
|
|
314
|
+
name: "OpLt",
|
|
315
|
+
pattern: /</
|
|
316
|
+
});
|
|
317
|
+
const OpGt = createToken({
|
|
318
|
+
name: "OpGt",
|
|
319
|
+
pattern: />/
|
|
320
|
+
});
|
|
321
|
+
const OpPlus = createToken({
|
|
322
|
+
name: "OpPlus",
|
|
323
|
+
pattern: /\+/
|
|
324
|
+
});
|
|
325
|
+
const OpMinus = createToken({
|
|
326
|
+
name: "OpMinus",
|
|
327
|
+
pattern: /-/
|
|
328
|
+
});
|
|
329
|
+
const OpMul = createToken({
|
|
330
|
+
name: "OpMul",
|
|
331
|
+
pattern: /\*/
|
|
332
|
+
});
|
|
333
|
+
const OpDiv = createToken({
|
|
334
|
+
name: "OpDiv",
|
|
335
|
+
pattern: /\//
|
|
336
|
+
});
|
|
337
|
+
const OpPow = createToken({
|
|
338
|
+
name: "OpPow",
|
|
339
|
+
pattern: /\^/
|
|
340
|
+
});
|
|
341
|
+
const OpConcat = createToken({
|
|
342
|
+
name: "OpConcat",
|
|
343
|
+
pattern: /&/
|
|
344
|
+
});
|
|
345
|
+
const OpPercent = createToken({
|
|
346
|
+
name: "OpPercent",
|
|
347
|
+
pattern: /%/
|
|
348
|
+
});
|
|
349
|
+
const LParen = createToken({
|
|
350
|
+
name: "LParen",
|
|
351
|
+
pattern: /\(/
|
|
352
|
+
});
|
|
353
|
+
const RParen = createToken({
|
|
354
|
+
name: "RParen",
|
|
355
|
+
pattern: /\)/
|
|
356
|
+
});
|
|
357
|
+
const Colon = createToken({
|
|
358
|
+
name: "Colon",
|
|
359
|
+
pattern: /:/
|
|
360
|
+
});
|
|
361
|
+
const Semicolon = createToken({
|
|
362
|
+
name: "Semicolon",
|
|
363
|
+
pattern: /;/
|
|
364
|
+
});
|
|
365
|
+
const Comma = createToken({
|
|
366
|
+
name: "Comma",
|
|
367
|
+
pattern: /,/
|
|
368
|
+
});
|
|
369
|
+
const Dot = createToken({
|
|
370
|
+
name: "Dot",
|
|
371
|
+
pattern: /\./
|
|
372
|
+
});
|
|
373
|
+
const allTokens = [
|
|
374
|
+
WhiteSpace,
|
|
375
|
+
StringLiteral,
|
|
376
|
+
ErrorLiteral,
|
|
377
|
+
FunctionName,
|
|
378
|
+
AbsoluteCell,
|
|
379
|
+
MixedCell,
|
|
380
|
+
RelativeCell,
|
|
381
|
+
ArrayLiteral,
|
|
382
|
+
NumberLiteral,
|
|
383
|
+
OpNe,
|
|
384
|
+
OpLe,
|
|
385
|
+
OpGe,
|
|
386
|
+
NotOp,
|
|
387
|
+
OpEq,
|
|
388
|
+
OpLt,
|
|
389
|
+
OpGt,
|
|
390
|
+
OpPlus,
|
|
391
|
+
OpMinus,
|
|
392
|
+
OpMul,
|
|
393
|
+
OpDiv,
|
|
394
|
+
OpPow,
|
|
395
|
+
OpConcat,
|
|
396
|
+
OpPercent,
|
|
397
|
+
LParen,
|
|
398
|
+
RParen,
|
|
399
|
+
Colon,
|
|
400
|
+
Semicolon,
|
|
401
|
+
Comma,
|
|
402
|
+
Dot,
|
|
403
|
+
Variable
|
|
404
|
+
];
|
|
405
|
+
const FormulaLexer = new Lexer(allTokens);
|
|
406
|
+
var FormulaParser = class extends EmbeddedActionsParser {
|
|
407
|
+
constructor() {
|
|
408
|
+
super(allTokens);
|
|
409
|
+
const $ = this;
|
|
410
|
+
$.RULE("expression", () => $.SUBRULE($.equality));
|
|
411
|
+
$.RULE("equality", () => {
|
|
412
|
+
let left = $.SUBRULE($.relational);
|
|
413
|
+
$.MANY(() => {
|
|
414
|
+
$.CONSUME(OpEq);
|
|
415
|
+
const right = $.SUBRULE2($.relational);
|
|
416
|
+
left = $.yy.evaluateByOperator("=", [left, right]);
|
|
417
|
+
});
|
|
418
|
+
return left;
|
|
419
|
+
});
|
|
420
|
+
$.RULE("relational", () => {
|
|
421
|
+
let left = $.SUBRULE($.additive);
|
|
422
|
+
$.MANY(() => {
|
|
423
|
+
const op = $.OR([
|
|
424
|
+
{ ALT: () => {
|
|
425
|
+
$.CONSUME(OpLe);
|
|
426
|
+
return "<=";
|
|
427
|
+
} },
|
|
428
|
+
{ ALT: () => {
|
|
429
|
+
$.CONSUME(OpGe);
|
|
430
|
+
return ">=";
|
|
431
|
+
} },
|
|
432
|
+
{ ALT: () => {
|
|
433
|
+
$.CONSUME(OpNe);
|
|
434
|
+
return "<>";
|
|
435
|
+
} },
|
|
436
|
+
{ ALT: () => {
|
|
437
|
+
$.CONSUME(NotOp);
|
|
438
|
+
return "NOT";
|
|
439
|
+
} },
|
|
440
|
+
{ ALT: () => {
|
|
441
|
+
$.CONSUME(OpLt);
|
|
442
|
+
return "<";
|
|
443
|
+
} },
|
|
444
|
+
{ ALT: () => {
|
|
445
|
+
$.CONSUME(OpGt);
|
|
446
|
+
return ">";
|
|
447
|
+
} }
|
|
448
|
+
]);
|
|
449
|
+
const right = $.SUBRULE2($.additive);
|
|
450
|
+
left = $.yy.evaluateByOperator(op, [left, right]);
|
|
451
|
+
});
|
|
452
|
+
return left;
|
|
453
|
+
});
|
|
454
|
+
$.RULE("additive", () => {
|
|
455
|
+
let left = $.SUBRULE($.multiplicative);
|
|
456
|
+
$.MANY(() => {
|
|
457
|
+
const op = $.OR([{ ALT: () => {
|
|
458
|
+
$.CONSUME(OpPlus);
|
|
459
|
+
return "+";
|
|
460
|
+
} }, { ALT: () => {
|
|
461
|
+
$.CONSUME(OpMinus);
|
|
462
|
+
return "-";
|
|
463
|
+
} }]);
|
|
464
|
+
const right = $.SUBRULE2($.multiplicative);
|
|
465
|
+
left = $.yy.evaluateByOperator(op, [left, right]);
|
|
466
|
+
});
|
|
467
|
+
return left;
|
|
468
|
+
});
|
|
469
|
+
$.RULE("multiplicative", () => {
|
|
470
|
+
let left = $.SUBRULE($.power);
|
|
471
|
+
$.MANY(() => {
|
|
472
|
+
const op = $.OR([{ ALT: () => {
|
|
473
|
+
$.CONSUME(OpMul);
|
|
474
|
+
return "*";
|
|
475
|
+
} }, { ALT: () => {
|
|
476
|
+
$.CONSUME(OpDiv);
|
|
477
|
+
return "/";
|
|
478
|
+
} }]);
|
|
479
|
+
const right = $.SUBRULE2($.power);
|
|
480
|
+
left = $.yy.evaluateByOperator(op, [left, right]);
|
|
481
|
+
});
|
|
482
|
+
return left;
|
|
483
|
+
});
|
|
484
|
+
$.RULE("power", () => {
|
|
485
|
+
let left = $.SUBRULE($.concat);
|
|
486
|
+
$.MANY(() => {
|
|
487
|
+
$.CONSUME(OpPow);
|
|
488
|
+
const right = $.SUBRULE2($.concat);
|
|
489
|
+
left = $.yy.evaluateByOperator("^", [left, right]);
|
|
490
|
+
});
|
|
491
|
+
return left;
|
|
492
|
+
});
|
|
493
|
+
$.RULE("concat", () => {
|
|
494
|
+
let left = $.SUBRULE($.unary);
|
|
495
|
+
$.MANY(() => {
|
|
496
|
+
$.CONSUME(OpConcat);
|
|
497
|
+
const right = $.SUBRULE2($.unary);
|
|
498
|
+
left = $.yy.evaluateByOperator("&", [left, right]);
|
|
499
|
+
});
|
|
500
|
+
return left;
|
|
501
|
+
});
|
|
502
|
+
$.RULE("unary", () => $.OR([
|
|
503
|
+
{ ALT: () => {
|
|
504
|
+
$.CONSUME(OpMinus);
|
|
505
|
+
const value = $.SUBRULE($.unary);
|
|
506
|
+
let n1 = $.yy.invertNumber(value);
|
|
507
|
+
if (isNaN(n1)) n1 = 0;
|
|
508
|
+
return n1;
|
|
509
|
+
} },
|
|
510
|
+
{ ALT: () => {
|
|
511
|
+
$.CONSUME(OpPlus);
|
|
512
|
+
let n1 = $.yy.toNumber($.SUBRULE2($.unary));
|
|
513
|
+
if (isNaN(n1)) n1 = 0;
|
|
514
|
+
return n1;
|
|
515
|
+
} },
|
|
516
|
+
{ ALT: () => $.SUBRULE($.primary) }
|
|
517
|
+
]));
|
|
518
|
+
$.RULE("primary", () => $.OR([
|
|
519
|
+
{ ALT: () => $.SUBRULE($.number) },
|
|
520
|
+
{ ALT: () => {
|
|
521
|
+
const tok = $.CONSUME(StringLiteral);
|
|
522
|
+
return $.yy.trimEdges(tok.image);
|
|
523
|
+
} },
|
|
524
|
+
{ ALT: () => $.SUBRULE($.cell) },
|
|
525
|
+
{ ALT: () => $.SUBRULE($.functionCall) },
|
|
526
|
+
{ ALT: () => $.SUBRULE($.variableSequence) },
|
|
527
|
+
{ ALT: () => {
|
|
528
|
+
$.CONSUME(LParen);
|
|
529
|
+
const value = $.SUBRULE($.expression);
|
|
530
|
+
$.CONSUME(RParen);
|
|
531
|
+
return value;
|
|
532
|
+
} },
|
|
533
|
+
{ ALT: () => $.SUBRULE($.error) }
|
|
534
|
+
]));
|
|
535
|
+
$.RULE("number", () => {
|
|
536
|
+
let value = $.yy.toNumber($.CONSUME(NumberLiteral).image);
|
|
537
|
+
$.OPTION(() => {
|
|
538
|
+
$.CONSUME(OpPercent);
|
|
539
|
+
value *= .01;
|
|
540
|
+
});
|
|
541
|
+
return value;
|
|
542
|
+
});
|
|
543
|
+
$.RULE("cell", () => {
|
|
544
|
+
const start = $.OR([
|
|
545
|
+
{ ALT: () => $.CONSUME(AbsoluteCell).image },
|
|
546
|
+
{ ALT: () => $.CONSUME(MixedCell).image },
|
|
547
|
+
{ ALT: () => $.CONSUME(RelativeCell).image }
|
|
548
|
+
]);
|
|
549
|
+
const end = $.OPTION(() => {
|
|
550
|
+
$.CONSUME(Colon);
|
|
551
|
+
return $.OR2([
|
|
552
|
+
{ ALT: () => $.CONSUME2(AbsoluteCell).image },
|
|
553
|
+
{ ALT: () => $.CONSUME2(MixedCell).image },
|
|
554
|
+
{ ALT: () => $.CONSUME2(RelativeCell).image }
|
|
555
|
+
]);
|
|
556
|
+
});
|
|
557
|
+
if (end) return $.yy.rangeValue(start, end);
|
|
558
|
+
return $.yy.cellValue(start);
|
|
559
|
+
});
|
|
560
|
+
$.RULE("functionCall", () => {
|
|
561
|
+
const name = $.CONSUME(FunctionName).image;
|
|
562
|
+
$.CONSUME(LParen);
|
|
563
|
+
const args = $.OPTION(() => $.SUBRULE($.expseq));
|
|
564
|
+
$.CONSUME(RParen);
|
|
565
|
+
return args ? $.yy.callFunction(name, args) : $.yy.callFunction(name);
|
|
566
|
+
});
|
|
567
|
+
$.RULE("expseq", () => $.OR([{ ALT: () => {
|
|
568
|
+
const tok = $.CONSUME(ArrayLiteral);
|
|
569
|
+
return $.yy.trimEdges(tok.image).split(",");
|
|
570
|
+
} }, { ALT: () => {
|
|
571
|
+
const args = [$.SUBRULE($.expression)];
|
|
572
|
+
$.MANY(() => {
|
|
573
|
+
$.OR2([{ ALT: () => $.CONSUME(Comma) }, { ALT: () => $.CONSUME(Semicolon) }]);
|
|
574
|
+
args.push($.SUBRULE2($.expression));
|
|
575
|
+
});
|
|
576
|
+
return args;
|
|
577
|
+
} }]));
|
|
578
|
+
$.RULE("variableSequence", () => {
|
|
579
|
+
const parts = [$.CONSUME(Variable).image];
|
|
580
|
+
$.MANY(() => {
|
|
581
|
+
$.CONSUME(Dot);
|
|
582
|
+
parts.push($.CONSUME2(Variable).image);
|
|
583
|
+
});
|
|
584
|
+
return $.yy.callVariable(parts[0]);
|
|
585
|
+
});
|
|
586
|
+
$.RULE("error", () => {
|
|
587
|
+
const tok = $.CONSUME(ErrorLiteral);
|
|
588
|
+
$.OPTION(() => $.CONSUME2(ErrorLiteral));
|
|
589
|
+
return $.yy.throwError(tok.image);
|
|
590
|
+
});
|
|
591
|
+
this.yy = {
|
|
592
|
+
evaluateByOperator: () => null,
|
|
593
|
+
toNumber: (v) => v,
|
|
594
|
+
invertNumber: (v) => v,
|
|
595
|
+
trimEdges: (v) => v,
|
|
596
|
+
throwError: () => null,
|
|
597
|
+
callVariable: () => null,
|
|
598
|
+
callFunction: () => null,
|
|
599
|
+
cellValue: () => null,
|
|
600
|
+
rangeValue: () => null
|
|
601
|
+
};
|
|
602
|
+
this.performSelfAnalysis();
|
|
603
|
+
}
|
|
604
|
+
};
|
|
605
|
+
/**
|
|
606
|
+
* Drop-in replacement for the old jison GrammarParser.
|
|
607
|
+
* Exposes `.yy` hooks and `.parse(input)`.
|
|
608
|
+
*/
|
|
609
|
+
function Parser$1() {
|
|
610
|
+
this.yy = {};
|
|
611
|
+
this._parser = new FormulaParser();
|
|
612
|
+
}
|
|
613
|
+
Parser$1.prototype.parse = function parse(input) {
|
|
614
|
+
if (typeof input !== "string") throw new Error("Parser error");
|
|
615
|
+
const lexResult = FormulaLexer.tokenize(input);
|
|
616
|
+
if (lexResult.errors.length > 0) throw new Error(lexResult.errors[0].message || "Lexer error");
|
|
617
|
+
this._parser.yy = this.yy;
|
|
618
|
+
this._parser.input = lexResult.tokens;
|
|
619
|
+
const result = this._parser.expression();
|
|
620
|
+
if (this._parser.errors.length > 0) {
|
|
621
|
+
const err = this._parser.errors[0];
|
|
622
|
+
throw new Error(err.message || "Parser error");
|
|
623
|
+
}
|
|
624
|
+
return result;
|
|
625
|
+
};
|
|
626
|
+
Parser$1.prototype.Parser = Parser$1;
|
|
627
|
+
//#endregion
|
|
628
|
+
//#region packages/formula-parser/src/helper/string.js
|
|
629
|
+
/**
|
|
630
|
+
* Trim value by cutting character starting from the beginning and ending at the same time.
|
|
631
|
+
*
|
|
632
|
+
* @param {String} string String to trimming.
|
|
633
|
+
* @param {Number} [margin=1] Number of character to cut.
|
|
634
|
+
* @returns {String}
|
|
635
|
+
*/
|
|
636
|
+
function trimEdges(string, margin = 1) {
|
|
637
|
+
string = string.substring(margin, string.length - margin);
|
|
638
|
+
return string;
|
|
639
|
+
}
|
|
640
|
+
//#endregion
|
|
641
|
+
//#region packages/formula-parser/src/helper/cell.js
|
|
642
|
+
/**
|
|
643
|
+
* Convert row label to index.
|
|
644
|
+
*
|
|
645
|
+
* @param {String} label Row label (eq. '1', '5')
|
|
646
|
+
* @returns {Number} Returns -1 if label is not recognized otherwise proper row index.
|
|
647
|
+
*/
|
|
648
|
+
function rowLabelToIndex(label) {
|
|
649
|
+
let result = parseInt(label, 10);
|
|
650
|
+
if (isNaN(result)) result = -1;
|
|
651
|
+
else result = Math.max(result - 1, -1);
|
|
652
|
+
return result;
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Convert row index to label.
|
|
656
|
+
*
|
|
657
|
+
* @param {Number} row Row index.
|
|
658
|
+
* @returns {String} Returns row label (eq. '1', '7').
|
|
659
|
+
*/
|
|
660
|
+
function rowIndexToLabel(row) {
|
|
661
|
+
let result = "";
|
|
662
|
+
if (row >= 0) result = `${row + 1}`;
|
|
663
|
+
return result;
|
|
664
|
+
}
|
|
665
|
+
const COLUMN_LABEL_BASE = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
|
666
|
+
const COLUMN_LABEL_BASE_LENGTH = 26;
|
|
667
|
+
/**
|
|
668
|
+
* Convert column label to index.
|
|
669
|
+
*
|
|
670
|
+
* @param {String} label Column label (eq. 'ABB', 'CNQ')
|
|
671
|
+
* @returns {Number} Returns -1 if label is not recognized otherwise proper column index.
|
|
672
|
+
*/
|
|
673
|
+
function columnLabelToIndex(label) {
|
|
674
|
+
let result = 0;
|
|
675
|
+
if (typeof label === "string") {
|
|
676
|
+
label = label.toUpperCase();
|
|
677
|
+
for (let i = 0, j = label.length - 1; i < label.length; i += 1, j -= 1) result += Math.pow(COLUMN_LABEL_BASE_LENGTH, j) * (COLUMN_LABEL_BASE.indexOf(label[i]) + 1);
|
|
678
|
+
}
|
|
679
|
+
--result;
|
|
680
|
+
return result;
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Convert column index to label.
|
|
684
|
+
*
|
|
685
|
+
* @param {Number} column Column index.
|
|
686
|
+
* @returns {String} Returns column label (eq. 'ABB', 'CNQ').
|
|
687
|
+
*/
|
|
688
|
+
function columnIndexToLabel(column) {
|
|
689
|
+
let result = "";
|
|
690
|
+
while (column >= 0) {
|
|
691
|
+
result = String.fromCharCode(column % COLUMN_LABEL_BASE_LENGTH + 97) + result;
|
|
692
|
+
column = Math.floor(column / COLUMN_LABEL_BASE_LENGTH) - 1;
|
|
693
|
+
}
|
|
694
|
+
return result.toUpperCase();
|
|
695
|
+
}
|
|
696
|
+
const LABEL_EXTRACT_REGEXP = new RegExp(`^(?:([A-Za-z0-9_À-ʯ]+|'(?:(?!').|'')*')!)?([$])?([A-Za-z]*)([$])?([0-9]*)$`);
|
|
697
|
+
/**
|
|
698
|
+
* Extract cell coordinates.
|
|
699
|
+
*
|
|
700
|
+
* @param {String} label Cell coordinates (eq. 'A1', '$B6', '$N$98').
|
|
701
|
+
* @returns {Array} Returns an array of objects.
|
|
702
|
+
*/
|
|
703
|
+
function extractLabel(label) {
|
|
704
|
+
if (typeof label !== "string" || !LABEL_EXTRACT_REGEXP.test(label)) return [];
|
|
705
|
+
const [, sheetNameStr, columnAbs, column, rowAbs, row] = label.toUpperCase().match(LABEL_EXTRACT_REGEXP);
|
|
706
|
+
if (column == null && row == null) return [];
|
|
707
|
+
const sheetName = sheetNameStr == null ? null : label.slice(0, sheetNameStr.length).replace(/^'|'$/g, "").replace(/''/g, "'");
|
|
708
|
+
return [
|
|
709
|
+
{
|
|
710
|
+
index: rowLabelToIndex(row),
|
|
711
|
+
label: row,
|
|
712
|
+
isAbsolute: rowAbs === "$"
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
index: columnLabelToIndex(column),
|
|
716
|
+
label: column,
|
|
717
|
+
isAbsolute: columnAbs === "$"
|
|
718
|
+
},
|
|
719
|
+
sheetName
|
|
720
|
+
];
|
|
721
|
+
}
|
|
722
|
+
/**
|
|
723
|
+
* Convert row and column indexes into cell label.
|
|
724
|
+
*
|
|
725
|
+
* @param {Object} row Object with `index` and `isAbsolute` properties.
|
|
726
|
+
* @param {Object} column Object with `index` and `isAbsolute` properties.
|
|
727
|
+
* @returns {String} Returns cell label.
|
|
728
|
+
*/
|
|
729
|
+
function toLabel(row, column) {
|
|
730
|
+
const rowLabel = (row.isAbsolute ? "$" : "") + rowIndexToLabel(row.index);
|
|
731
|
+
return (column.isAbsolute ? "$" : "") + columnIndexToLabel(column.index) + rowLabel;
|
|
732
|
+
}
|
|
733
|
+
//#endregion
|
|
734
|
+
//#region packages/formula-parser/src/parser.js
|
|
735
|
+
/**
|
|
736
|
+
* @class Parser
|
|
737
|
+
*/
|
|
738
|
+
var Parser = class extends Emitter {
|
|
739
|
+
constructor() {
|
|
740
|
+
super();
|
|
741
|
+
this.parser = new Parser$1();
|
|
742
|
+
this.parser.yy = {
|
|
743
|
+
toNumber,
|
|
744
|
+
trimEdges,
|
|
745
|
+
invertNumber,
|
|
746
|
+
throwError: (errorName) => this._throwError(errorName),
|
|
747
|
+
callVariable: (variable) => this._callVariable(variable),
|
|
748
|
+
evaluateByOperator,
|
|
749
|
+
callFunction: (name, params) => this._callFunction(name, params),
|
|
750
|
+
cellValue: (value) => this._callCellValue(value),
|
|
751
|
+
rangeValue: (start, end) => this._callRangeValue(start, end)
|
|
752
|
+
};
|
|
753
|
+
this.variables = Object.create(null);
|
|
754
|
+
this.functions = Object.create(null);
|
|
755
|
+
this.options = Object.create(null);
|
|
756
|
+
this.setVariable("TRUE", true).setVariable("FALSE", false).setVariable("NULL", null);
|
|
757
|
+
}
|
|
758
|
+
/**
|
|
759
|
+
* Parse formula expression.
|
|
760
|
+
*
|
|
761
|
+
* @param {string} expression to parse.
|
|
762
|
+
* @param {object} options additional params.
|
|
763
|
+
* @param {string} options.sheetId id of sheet which the formula expression belongs to.
|
|
764
|
+
* @return {*} Returns an object with tow properties `error` and `result`.
|
|
765
|
+
*/
|
|
766
|
+
parse(expression, options) {
|
|
767
|
+
let result = null;
|
|
768
|
+
let error$1 = null;
|
|
769
|
+
this.options = options;
|
|
770
|
+
try {
|
|
771
|
+
if (expression === "") result = "";
|
|
772
|
+
else result = this.parser.parse(expression);
|
|
773
|
+
} catch (ex) {
|
|
774
|
+
const message = error(ex.message);
|
|
775
|
+
if (message) error$1 = message;
|
|
776
|
+
else error$1 = error(ERROR);
|
|
777
|
+
}
|
|
778
|
+
if (result instanceof Error) {
|
|
779
|
+
error$1 = error(result.message) || error("ERROR");
|
|
780
|
+
result = null;
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
error: error$1,
|
|
784
|
+
result
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
/**
|
|
788
|
+
* Set predefined variable name which can be visible while parsing formula expression.
|
|
789
|
+
*
|
|
790
|
+
* @param {String} name Variable name.
|
|
791
|
+
* @param {*} value Variable value.
|
|
792
|
+
* @returns {Parser}
|
|
793
|
+
*/
|
|
794
|
+
setVariable(name, value) {
|
|
795
|
+
this.variables[name] = value;
|
|
796
|
+
return this;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* Get variable name.
|
|
800
|
+
*
|
|
801
|
+
* @param {String} name Variable name.
|
|
802
|
+
* @returns {*}
|
|
803
|
+
*/
|
|
804
|
+
getVariable(name) {
|
|
805
|
+
return this.variables[name];
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Retrieve variable value by its name.
|
|
809
|
+
*
|
|
810
|
+
* @param name Variable name.
|
|
811
|
+
* @returns {*}
|
|
812
|
+
* @private
|
|
813
|
+
*/
|
|
814
|
+
_callVariable(name) {
|
|
815
|
+
let value = this.getVariable(name);
|
|
816
|
+
this.emit("callVariable", name, (newValue) => {
|
|
817
|
+
if (newValue !== void 0) value = newValue;
|
|
818
|
+
});
|
|
819
|
+
if (value === void 0) throw Error(ERROR_NAME);
|
|
820
|
+
return value;
|
|
821
|
+
}
|
|
822
|
+
/**
|
|
823
|
+
* Set custom function which can be visible while parsing formula expression.
|
|
824
|
+
*
|
|
825
|
+
* @param {String} name Custom function name.
|
|
826
|
+
* @param {Function} fn Custom function.
|
|
827
|
+
* @returns {Parser}
|
|
828
|
+
*/
|
|
829
|
+
setFunction(name, fn) {
|
|
830
|
+
this.functions[name] = fn;
|
|
831
|
+
return this;
|
|
832
|
+
}
|
|
833
|
+
/**
|
|
834
|
+
* Get custom function.
|
|
835
|
+
*
|
|
836
|
+
* @param {String} name Custom function name.
|
|
837
|
+
* @returns {*}
|
|
838
|
+
*/
|
|
839
|
+
getFunction(name) {
|
|
840
|
+
return this.functions[name];
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Call function with provided params.
|
|
844
|
+
*
|
|
845
|
+
* @param name Function name.
|
|
846
|
+
* @param params Function params.
|
|
847
|
+
* @returns {*}
|
|
848
|
+
* @private
|
|
849
|
+
*/
|
|
850
|
+
_callFunction(name, params = []) {
|
|
851
|
+
const fn = this.getFunction(name);
|
|
852
|
+
let value;
|
|
853
|
+
if (fn) value = fn(params);
|
|
854
|
+
this.emit("callFunction", name, params, (newValue) => {
|
|
855
|
+
if (newValue !== void 0) value = newValue;
|
|
856
|
+
});
|
|
857
|
+
return value === void 0 ? evaluateByOperator(name, params) : value;
|
|
858
|
+
}
|
|
859
|
+
/**
|
|
860
|
+
* Retrieve value by its label (`B3`, `B$3`, `B$3`, `$B$3`).
|
|
861
|
+
*
|
|
862
|
+
* @param {String} label Coordinates.
|
|
863
|
+
* @returns {*}
|
|
864
|
+
* @private
|
|
865
|
+
*/
|
|
866
|
+
_callCellValue(label) {
|
|
867
|
+
const [row, column, sheetName] = extractLabel(label);
|
|
868
|
+
if (column?.index === -1) {
|
|
869
|
+
if (row.isAbsolute || column.isAbsolute) throw Error(ERROR_NAME);
|
|
870
|
+
return row.index + 1;
|
|
871
|
+
} else if (row?.index === -1) throw Error(ERROR_NAME);
|
|
872
|
+
let value = void 0;
|
|
873
|
+
const normalizedLabel = toLabel(row, column);
|
|
874
|
+
this.emit("callCellValue", {
|
|
875
|
+
label: normalizedLabel,
|
|
876
|
+
row,
|
|
877
|
+
column,
|
|
878
|
+
sheetName
|
|
879
|
+
}, this.options, (_value) => {
|
|
880
|
+
value = _value;
|
|
881
|
+
});
|
|
882
|
+
return value;
|
|
883
|
+
}
|
|
884
|
+
/**
|
|
885
|
+
* Retrieve value by its label (`B3:A1`, `B$3:A1`, `B$3:$A1`, `$B$3:A$1`).
|
|
886
|
+
*
|
|
887
|
+
* @param {String} startLabel Coordinates of the first cell.
|
|
888
|
+
* @param {String} endLabel Coordinates of the last cell.
|
|
889
|
+
* @returns {Array} Returns an array of mixed values.
|
|
890
|
+
* @private
|
|
891
|
+
*/
|
|
892
|
+
_callRangeValue(startLabel, endLabel) {
|
|
893
|
+
const [startRow, startColumn, startSheetName] = extractLabel(startLabel);
|
|
894
|
+
const [endRow, endColumn, endSheetName] = extractLabel(endLabel);
|
|
895
|
+
if (endSheetName != null && startSheetName != endSheetName) throw Error(ERROR_VALUE);
|
|
896
|
+
let startCell = {};
|
|
897
|
+
let endCell = {};
|
|
898
|
+
startCell.sheetName = startSheetName;
|
|
899
|
+
if (startRow.index <= endRow.index) {
|
|
900
|
+
startCell.row = startRow;
|
|
901
|
+
endCell.row = endRow;
|
|
902
|
+
} else {
|
|
903
|
+
startCell.row = endRow;
|
|
904
|
+
endCell.row = startRow;
|
|
905
|
+
}
|
|
906
|
+
if (startColumn.index <= endColumn.index) {
|
|
907
|
+
startCell.column = startColumn;
|
|
908
|
+
endCell.column = endColumn;
|
|
909
|
+
} else {
|
|
910
|
+
startCell.column = endColumn;
|
|
911
|
+
endCell.column = startColumn;
|
|
912
|
+
}
|
|
913
|
+
startCell.label = toLabel(startCell.row, startCell.column);
|
|
914
|
+
endCell.label = toLabel(endCell.row, endCell.column);
|
|
915
|
+
let value = [];
|
|
916
|
+
this.emit("callRangeValue", startCell, endCell, this.options, (_value = []) => {
|
|
917
|
+
value = _value;
|
|
918
|
+
});
|
|
919
|
+
return value;
|
|
920
|
+
}
|
|
921
|
+
/**
|
|
922
|
+
* Try to throw error by its name.
|
|
923
|
+
*
|
|
924
|
+
* @param {String} errorName Error name.
|
|
925
|
+
* @returns {String}
|
|
926
|
+
* @private
|
|
927
|
+
*/
|
|
928
|
+
_throwError(errorName) {
|
|
929
|
+
if (isValidStrict(errorName)) throw Error(errorName);
|
|
930
|
+
throw Error(ERROR);
|
|
931
|
+
}
|
|
932
|
+
};
|
|
933
|
+
//#endregion
|
|
934
|
+
export { ERROR, ERROR_DIV_ZERO, ERROR_NAME, ERROR_NOT_AVAILABLE, ERROR_NULL, ERROR_NUM, ERROR_REF, ERROR_VALUE, Parser, SUPPORTED_FORMULAS, columnIndexToLabel, columnLabelToIndex, error, extractLabel, rowIndexToLabel, rowLabelToIndex, toLabel };
|