commit
message
[ALL] Criteria evaluations accept dollar-to-number comparisons, eg '>=-0'
author
Ben Vogt <[email protected]>
date
2017-04-02 19:45:27
stats
3 file(s) changed,
13 insertions(+),
17 deletions(-)
files
README.md
src/RawFormulas/Utils.ts
tests/FormulasTest.ts
1diff --git a/README.md b/README.md
2index 8d52f4a..75c9673 100644
3--- a/README.md
4+++ b/README.md
5@@ -7,16 +7,8 @@ Things I should do.
6 ### SUM and SUMA should be different, and I'm pretty sure they're currently the same.
7 And the same for MAX, MAXA, COUNT, COUNTA, etc. Look these over.
8
9-### Protect against injection
10-How do we protect against users injecting data that looks like `console.log(sensitive_data)` when we evaluate variables
11-inside parser.js? If we ever want to impliment custom formulas, or even accept data in raw format, we need to guard
12-against this. Or else someone could load a CSV with javascript and when our spreadsheet opens it, then suddenly
13-arbitrary javascript is executed in the client machine.
14-
15 ### Criteria evaluations should escape reg-ex characters: http://stackoverflow.com/questions/3446170/escape-string-for-use-in-javascript-regex
16
17-### Criteria evaluations should accept dollar-to-number comparisons: `=COUNTIF({10, 20, 40}, ">=$20")`
18-
19 ### License for all code used.
20
21 ### Document the functions pulled in from jStat.
22diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
23index 18f8037..51712a4 100644
24--- a/src/RawFormulas/Utils.ts
25+++ b/src/RawFormulas/Utils.ts
26@@ -294,20 +294,19 @@ class CriteriaFunctionFactory {
27 return x === criteria;
28 };
29 } else if (typeof criteria === "string") {
30- // https://regex101.com/r/c2hxAZ/6
31- var comparisonMatches = criteria.match(/(^<=|^>=|^=|^<>|^>|^<)\s*(-?[0-9]+([,.][0-9]+)?)\s*$/);
32- if (comparisonMatches !== null && comparisonMatches.length >= 4 && comparisonMatches[2] !== undefined) {
33+ var comparisonMatches = criteria.match(/^\s*(<=|>=|=|<>|>|<)\s*(-)?\s*(\$)?\s*([0-9]+([,.][0-9]+)?)\s*$/);
34+ if (comparisonMatches !== null && comparisonMatches.length >= 6 && comparisonMatches[4] !== undefined) {
35 criteriaEvaluation = function (x) : boolean {
36- return eval(x + criteria);
37+ return eval(x + comparisonMatches[1] + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
38 };
39 if (comparisonMatches[1] === "=") {
40 criteriaEvaluation = function (x) : boolean {
41- return eval(x + "===" + comparisonMatches[2]);
42+ return eval(x + "===" + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
43 };
44 }
45 if (comparisonMatches[1] === "<>") {
46 criteriaEvaluation = function (x) : boolean {
47- return eval(x + "!==" + comparisonMatches[2]);
48+ return eval(x + "!==" + (comparisonMatches[2] === undefined ? "" : "-") + comparisonMatches[4]);
49 };
50 }
51 } else if (criteria.match(/\*|\~\*|\?|\~\?/) !== null) {
52diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
53index d49c1d6..6c65bf3 100644
54--- a/tests/FormulasTest.ts
55+++ b/tests/FormulasTest.ts
56@@ -643,6 +643,13 @@ assertEquals(COUNTIF(["mom", "pop", "dad", "etc", "mom"], "?o?"), 3);
57 assertEquals(COUNTIF(["mom", "pop", "dad", "etc", "mom"], "???"), 5);
58 assertEquals(COUNTIF(["mom", "pop", "dad", "etc", "mom"], "????"), 0);
59 assertEquals(COUNTIF(["mom", "pop", "dad", "etc", "mom"], "?"), 0);
60+// dollar sign and negative values
61+assertEquals(COUNTIF([1, 5, 5, 5, 10, 5], "=$5"), 4);
62+assertEquals(COUNTIF([1, -5, -5, -5, 10, -5], "=-$5"), 4);
63+assertEquals(COUNTIF([1, -5, -5, -5, 10, -5], "=-5"), 4);
64+assertEquals(COUNTIF([1, 5, 5, 5, 10, 5], ">$5"), 1);
65+assertEquals(COUNTIF([1, 5, 5, 5, 10, 5], "=$10"), 1);
66+assertEquals(COUNTIF([1, 5, 5, 5, 10, 5], "= $ 10"), 1);
67 catchAndAssertEquals(function() {
68 COUNTIF([0, 1, 0, 1]);
69 }, ERRORS.NA_ERROR);