@lofcz/tinysheet-formula-parser 0.2.13 → 1.0.3

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 (49) hide show
  1. package/dist/index.d.ts +46 -0
  2. package/dist/index.js +934 -0
  3. package/package.json +19 -41
  4. package/es/error.js +0 -45
  5. package/es/evaluate-by-operator/evaluate-by-operator.js +0 -70
  6. package/es/evaluate-by-operator/operator/add.js +0 -16
  7. package/es/evaluate-by-operator/operator/ampersand.js +0 -10
  8. package/es/evaluate-by-operator/operator/divide.js +0 -21
  9. package/es/evaluate-by-operator/operator/equal.js +0 -5
  10. package/es/evaluate-by-operator/operator/formula-function.js +0 -40
  11. package/es/evaluate-by-operator/operator/greater-than-or-equal.js +0 -5
  12. package/es/evaluate-by-operator/operator/greater-than.js +0 -5
  13. package/es/evaluate-by-operator/operator/less-than-or-equal.js +0 -5
  14. package/es/evaluate-by-operator/operator/less-than.js +0 -5
  15. package/es/evaluate-by-operator/operator/minus.js +0 -16
  16. package/es/evaluate-by-operator/operator/multiply.js +0 -16
  17. package/es/evaluate-by-operator/operator/not-equal.js +0 -5
  18. package/es/evaluate-by-operator/operator/power.js +0 -11
  19. package/es/grammar-parser/grammar-parser.jison +0 -230
  20. package/es/grammar-parser/grammar-parser.js +0 -1522
  21. package/es/helper/cell.js +0 -117
  22. package/es/helper/number.js +0 -25
  23. package/es/helper/string.js +0 -13
  24. package/es/index.js +0 -5
  25. package/es/parser.js +0 -306
  26. package/es/supported-formulas.js +0 -3
  27. package/lib/error.js +0 -53
  28. package/lib/evaluate-by-operator/evaluate-by-operator.js +0 -77
  29. package/lib/evaluate-by-operator/operator/add.js +0 -23
  30. package/lib/evaluate-by-operator/operator/ampersand.js +0 -17
  31. package/lib/evaluate-by-operator/operator/divide.js +0 -28
  32. package/lib/evaluate-by-operator/operator/equal.js +0 -12
  33. package/lib/evaluate-by-operator/operator/formula-function.js +0 -50
  34. package/lib/evaluate-by-operator/operator/greater-than-or-equal.js +0 -12
  35. package/lib/evaluate-by-operator/operator/greater-than.js +0 -12
  36. package/lib/evaluate-by-operator/operator/less-than-or-equal.js +0 -12
  37. package/lib/evaluate-by-operator/operator/less-than.js +0 -12
  38. package/lib/evaluate-by-operator/operator/minus.js +0 -23
  39. package/lib/evaluate-by-operator/operator/multiply.js +0 -23
  40. package/lib/evaluate-by-operator/operator/not-equal.js +0 -12
  41. package/lib/evaluate-by-operator/operator/power.js +0 -18
  42. package/lib/grammar-parser/grammar-parser.jison +0 -230
  43. package/lib/grammar-parser/grammar-parser.js +0 -1528
  44. package/lib/helper/cell.js +0 -128
  45. package/lib/helper/number.js +0 -32
  46. package/lib/helper/string.js +0 -19
  47. package/lib/index.js +0 -114
  48. package/lib/parser.js +0 -313
  49. 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 };