spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
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