commit
message
[ISNA] formula added and tested (IFERRORing correct calling from Parser/Sheet)
author
Ben Vogt <[email protected]>
date
2017-07-10 00:47:21
stats
11 file(s) changed,
121 insertions(+),
7 deletions(-)
files
DOCS.md
TODO.md
dist/Cell.js
dist/Formulas/AllFormulas.js
dist/Formulas/Info.js
src/Cell.ts
src/Formulas/AllFormulas.ts
src/Formulas/Info.ts
tests/Formulas/InfoTest.ts
tests/SheetFormulaTest.ts
tests/Utils/Asserts.ts
1diff --git a/DOCS.md b/DOCS.md
2index f8177dc..e370f67 100644
3--- a/DOCS.md
4+++ b/DOCS.md
5@@ -665,6 +665,16 @@
6 @returns {boolean}
7 @constructor TODO: This formula needs to be called from inside a try-catch-block in the SheetParser, like ERROR.TYPE.
8 ```
9+
10+### IFERROR
11+
12+```
13+ Returns the first argument if no error value is present, otherwise returns the second argument if provided, or a blank if the second argument is absent.
14+@param value - Value to check for error.
15+@param valueIfError - [OPTIONAL] - Value to return if no error is present in the first argument.
16+@returns {any}
17+@constructor TODO: This formula needs to be called from inside a try-catch-block in the SheetParser, like ERROR.TYPE.
18+```
19 ## Logical
20
21
22diff --git a/TODO.md b/TODO.md
23index 638cfab..e59ed99 100644
24--- a/TODO.md
25+++ b/TODO.md
26@@ -41,7 +41,6 @@ Many of these formulas can be written by allowing the Sheet and Parser to return
27 * ISFORMULA - Requires changes to Parser/Sheet to fetch a cell, and check the formula field to see if it contains a formula.
28 * TYPE - Requires changes to Parser/Sheet to allow for values or cells to be returned to the function. If it's a value, return the value type. If it's a cell, return the value or error inside it.
29 * CELL - Requires changes to Parser/Sheet so that the raw cell is returned to the function. The raw cell should contain all information necessary for returning specified info.
30-* IFERROR - similar reasons to ISERR.
31 * ADDRESS
32 * COLUMN
33 * COLUMNS
34diff --git a/dist/Cell.js b/dist/Cell.js
35index 1ca488a..f7b249d 100644
36--- a/dist/Cell.js
37+++ b/dist/Cell.js
38@@ -146,6 +146,14 @@ var Cell = (function () {
39 Cell.prototype.toString = function () {
40 return "id=" + this.id + ", value=" + this.typedValue + ", rawFormulaText=" + this.rawFormulaText + ", error=" + this.error;
41 };
42+ /**
43+ * Comparing two cells.
44+ * @param other
45+ * @returns {boolean}
46+ */
47+ Cell.prototype.equals = function (other) {
48+ return this.toString() === other.toString();
49+ };
50 /**
51 * Build a cell with an id and value.
52 * @param id - A1-notation id or key.
53diff --git a/dist/Formulas/AllFormulas.js b/dist/Formulas/AllFormulas.js
54index 53c0b95..33b01f3 100644
55--- a/dist/Formulas/AllFormulas.js
56+++ b/dist/Formulas/AllFormulas.js
57@@ -94,6 +94,7 @@ exports.ISBLANK = Info_1.ISBLANK;
58 exports.ISERR = Info_1.ISERR;
59 exports.ISERROR = Info_1.ISERROR;
60 exports.ISNA = Info_1.ISNA;
61+exports.IFERROR = Info_1.IFERROR;
62 var Lookup_1 = require("./Lookup");
63 exports.CHOOSE = Lookup_1.CHOOSE;
64 var Logical_1 = require("./Logical");
65diff --git a/dist/Formulas/Info.js b/dist/Formulas/Info.js
66index cdf0d9b..d0d5466 100644
67--- a/dist/Formulas/Info.js
68+++ b/dist/Formulas/Info.js
69@@ -205,6 +205,7 @@ exports.ISBLANK = ISBLANK;
70 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
71 */
72 var ISERR = function (value) {
73+ ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ISERR");
74 if (value instanceof Cell_1.Cell) {
75 if (value.hasError()) {
76 return value.getError().name !== Errors_1.NA_ERROR;
77@@ -226,6 +227,7 @@ exports.ISERR = ISERR;
78 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
79 */
80 var ISERROR = function (value) {
81+ ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ISERROR");
82 try {
83 value = TypeConverter_1.TypeConverter.firstValue(value);
84 }
85@@ -247,6 +249,7 @@ exports.ISERROR = ISERROR;
86 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
87 */
88 var ISNA = function (value) {
89+ ArgsChecker_1.ArgsChecker.checkLength(arguments, 1, "ISNA");
90 try {
91 value = TypeConverter_1.TypeConverter.firstValue(value);
92 }
93@@ -264,3 +267,20 @@ var ISNA = function (value) {
94 return false;
95 };
96 exports.ISNA = ISNA;
97+/**
98+ * Returns the first argument if no error value is present, otherwise returns the second argument if provided, or a
99+ * blank if the second argument is absent.
100+ * @param value - Value to check for error.
101+ * @param valueIfError - [OPTIONAL] - Value to return if no error is present in the first argument.
102+ * @returns {any}
103+ * @constructor
104+ * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
105+ */
106+var IFERROR = function (value, valueIfError) {
107+ ArgsChecker_1.ArgsChecker.checkLengthWithin(arguments, 1, 2, "IFERROR");
108+ if (value instanceof Cell_1.Cell && valueIfError === undefined) {
109+ return ISERROR(value) ? new Cell_1.Cell(value.getId()) : value;
110+ }
111+ return ISERROR(value) ? valueIfError : value;
112+};
113+exports.IFERROR = IFERROR;
114diff --git a/src/Cell.ts b/src/Cell.ts
115index ff6af9a..89d781e 100644
116--- a/src/Cell.ts
117+++ b/src/Cell.ts
118@@ -165,6 +165,15 @@ class Cell {
119 return "id=" + this.id + ", value=" + this.typedValue + ", rawFormulaText=" + this.rawFormulaText + ", error=" + this.error;
120 }
121
122+ /**
123+ * Comparing two cells.
124+ * @param other
125+ * @returns {boolean}
126+ */
127+ equals(other : Cell) : boolean {
128+ return this.toString() === other.toString();
129+ }
130+
131 /**
132 * Build a cell with an id and value.
133 * @param id - A1-notation id or key.
134diff --git a/src/Formulas/AllFormulas.ts b/src/Formulas/AllFormulas.ts
135index ee47e91..6747737 100644
136--- a/src/Formulas/AllFormulas.ts
137+++ b/src/Formulas/AllFormulas.ts
138@@ -93,7 +93,8 @@ import {
139 ISBLANK,
140 ISERR,
141 ISERROR,
142- ISNA
143+ ISNA,
144+ IFERROR
145 } from "./Info";
146 import {
147 CHOOSE
148@@ -437,5 +438,6 @@ export {
149 ISBLANK,
150 ISERR,
151 ISERROR,
152- ISNA
153+ ISNA,
154+ IFERROR
155 }
156\ No newline at end of file
157diff --git a/src/Formulas/Info.ts b/src/Formulas/Info.ts
158index 9413c3d..d5fffc0 100644
159--- a/src/Formulas/Info.ts
160+++ b/src/Formulas/Info.ts
161@@ -222,6 +222,7 @@ var ISBLANK = function (value) {
162 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
163 */
164 var ISERR = function (value) {
165+ ArgsChecker.checkLength(arguments, 1, "ISERR");
166 if (value instanceof Cell) {
167 if (value.hasError()) {
168 return value.getError().name !== NA_ERROR;
169@@ -243,6 +244,7 @@ var ISERR = function (value) {
170 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
171 */
172 var ISERROR = function (value) {
173+ ArgsChecker.checkLength(arguments, 1, "ISERROR");
174 try {
175 value = TypeConverter.firstValue(value);
176 } catch (e) {
177@@ -264,6 +266,7 @@ var ISERROR = function (value) {
178 * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
179 */
180 var ISNA = function (value) {
181+ ArgsChecker.checkLength(arguments, 1, "ISNA");
182 try {
183 value = TypeConverter.firstValue(value);
184 } catch (e) {
185@@ -281,6 +284,24 @@ var ISNA = function (value) {
186 };
187
188
189+/**
190+ * Returns the first argument if no error value is present, otherwise returns the second argument if provided, or a
191+ * blank if the second argument is absent.
192+ * @param value - Value to check for error.
193+ * @param valueIfError - [OPTIONAL] - Value to return if no error is present in the first argument.
194+ * @returns {any}
195+ * @constructor
196+ * TODO: This formula needs to be called from inside a try-catch-block in the Sheet/Parser, like ERROR.TYPE.
197+ */
198+var IFERROR = function (value, valueIfError?) {
199+ ArgsChecker.checkLengthWithin(arguments, 1, 2, "IFERROR");
200+ if (value instanceof Cell && valueIfError === undefined) {
201+ return ISERROR(value) ? new Cell(value.getId()) : value;
202+ }
203+ return ISERROR(value) ? valueIfError : value;
204+};
205+
206+
207 export {
208 NA,
209 ISTEXT,
210@@ -295,5 +316,6 @@ export {
211 ISBLANK,
212 ISERR,
213 ISERROR,
214- ISNA
215+ ISNA,
216+ IFERROR
217 }
218\ No newline at end of file
219diff --git a/tests/Formulas/InfoTest.ts b/tests/Formulas/InfoTest.ts
220index 0506e2f..3508e90 100644
221--- a/tests/Formulas/InfoTest.ts
222+++ b/tests/Formulas/InfoTest.ts
223@@ -12,7 +12,8 @@ import {
224 ISBLANK,
225 ISERR,
226 ISERROR,
227- ISNA
228+ ISNA,
229+ IFERROR
230 } from "../../src/Formulas/Info";
231 import * as ERRORS from "../../src/Errors";
232 import {
233@@ -179,6 +180,9 @@ test("ISERR", function(){
234 assertEquals(ISERR(new DivZeroError("error")), true);
235 assertEquals(ISERR(new NameError("error")), true);
236 assertEquals(ISERR(new RefError("error")), true);
237+ catchAndAssertEquals(function() {
238+ ISERR.apply(this, [])
239+ }, ERRORS.NA_ERROR);
240 });
241
242
243@@ -195,6 +199,9 @@ test("ISERROR", function(){
244 assertEquals(ISERROR(new DivZeroError("error")), true);
245 assertEquals(ISERROR(new NameError("error")), true);
246 assertEquals(ISERROR(new RefError("error")), true);
247+ catchAndAssertEquals(function() {
248+ ISERROR.apply(this, [])
249+ }, ERRORS.NA_ERROR);
250 });
251
252
253@@ -211,4 +218,20 @@ test("ISNA", function(){
254 assertEquals(ISNA(new DivZeroError("error")), false);
255 assertEquals(ISNA(new NameError("error")), false);
256 assertEquals(ISNA(new RefError("error")), false);
257+ catchAndAssertEquals(function() {
258+ ISNA.apply(this, [])
259+ }, ERRORS.NA_ERROR);
260+});
261+
262+
263+test("IFERROR", function(){
264+ var errorCell = new Cell("A1");
265+ errorCell.setError(new NAError("err"));
266+ assertEquals(IFERROR(errorCell, 10), 10);
267+ assertEquals(IFERROR(10), 10);
268+ assertEquals(IFERROR(Cell.BuildFrom("A1", 10), "abc"), Cell.BuildFrom("A1", 10));
269+ assertEquals(IFERROR(new Cell("A1")), new Cell("A1"));
270+ catchAndAssertEquals(function() {
271+ IFERROR.apply(this, [])
272+ }, ERRORS.NA_ERROR);
273 });
274diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
275index 7139791..238cbe5 100644
276--- a/tests/SheetFormulaTest.ts
277+++ b/tests/SheetFormulaTest.ts
278@@ -852,6 +852,10 @@ test("Sheet ISNA", function(){
279 assertFormulaEquals('=ISNA(10)', false);
280 });
281
282+test("Sheet IFERROR", function(){
283+ assertFormulaEquals('=IFERROR(10)', 10);
284+});
285+
286 test("Sheet *", function(){
287 assertFormulaEquals('= 10 * 10', 100);
288 assertFormulaEquals('= 10 * 0', 0);
289diff --git a/tests/Utils/Asserts.ts b/tests/Utils/Asserts.ts
290index 46163c9..4270deb 100644
291--- a/tests/Utils/Asserts.ts
292+++ b/tests/Utils/Asserts.ts
293@@ -1,12 +1,20 @@
294+import {Cell} from "../../src/Cell";
295 /**
296 * Assert two params are equal using strict equality testing.
297 * @param actual value
298 * @param expected value
299 */
300 function assertEquals(actual, expected) {
301- if (expected !== actual) {
302- console.log("expected:", expected, " actual:", actual);
303- console.trace();
304+ if (actual instanceof Cell && expected instanceof Cell) {
305+ if (!expected.equals(actual)) {
306+ console.log("expected:", expected, " actual:", actual);
307+ console.trace();
308+ }
309+ } else {
310+ if (expected !== actual) {
311+ console.log("expected:", expected, " actual:", actual);
312+ console.trace();
313+ }
314 }
315 }
316