spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Sheet, Errors] Standardizing use of errors
author
Ben Vogt <[email protected]>
date
2017-05-11 01:51:45
stats
5 file(s) changed, 58 insertions(+), 62 deletions(-)
files
src/Cell.ts
src/Errors.ts
src/Sheet.ts
tests/SheetFormulaTest.ts
tests/SheetTest.ts
  1diff --git a/src/Cell.ts b/src/Cell.ts
  2index 52fc98b..cecd7e7 100644
  3--- a/src/Cell.ts
  4+++ b/src/Cell.ts
  5@@ -10,7 +10,7 @@ class Cell {
  6   private rawFormulaText: string = null;
  7   private typedValue: any = null;
  8   private dependencies: Array<string> = [];
  9-  private error: string = null;
 10+  private error: Error = null;
 11   private id: string;
 12   private row: number;
 13   private col: number;
 14@@ -129,15 +129,15 @@ class Cell {
 15    * Set error for this cell. Usually in the case of a parse error when parsing the rawFormulaText.
 16    * @param error to set.
 17    */
 18-  setError(error: string) {
 19+  setError(error: Error) {
 20     this.error = error;
 21   }
 22 
 23   /**
 24    * Get the error for this cell. If the rawFormulaText is not parsed properly, or is null, this could be null.
 25-   * @returns {string} error to return, could be null.
 26+   * @returns {Error} error to return, could be null.
 27    */
 28-  getError() : string {
 29+  getError() : Error {
 30     return this.error;
 31   }
 32 
 33diff --git a/src/Errors.ts b/src/Errors.ts
 34index 9398717..b838c6f 100644
 35--- a/src/Errors.ts
 36+++ b/src/Errors.ts
 37@@ -6,35 +6,6 @@ var NAME_ERROR = "#NAME!";
 38 var NUM_ERROR = "#NUM!";
 39 var NA_ERROR = "#N/A";
 40 
 41-var Errors = {
 42-  errors: {
 43-    'NULL': '#NULL',
 44-    '#NULL': '#NULL',
 45-    'DIV_ZERO': '#DIV/0!',
 46-    '#DIV/0!': '#DIV/0!',
 47-    'VALUE': '#VALUE!',
 48-    '#VALUE!': '#VALUE!',
 49-    'REF': '#REF!',
 50-    '#REF!': '#REF!',
 51-    'NAME': '#NAME?',
 52-    '#NAME?': '#NAME?',
 53-    'NUM': '#NUM!',
 54-    '#NUM!': '#NUM!',
 55-    'NOT_AVAILABLE': '#N/A!',
 56-    '#N/A!': '#N/A!',
 57-    '#N/A': '#N/A',
 58-    'ERROR': '#ERROR',
 59-    '#ERROR': '#ERROR'
 60-  },
 61-  get: function (type) {
 62-    if (type in Errors.errors) {
 63-      return Errors.errors[type];
 64-    }
 65-    return null;
 66-  }
 67-};
 68-
 69-
 70 class NullError extends Error {
 71   constructor(message: string) {
 72     super(message);
 73@@ -85,7 +56,6 @@ class NAError extends Error {
 74 }
 75 
 76 export {
 77-  Errors,
 78   DIV_ZERO_ERROR,
 79   NULL_ERROR,
 80   VALUE_ERROR,
 81diff --git a/src/Sheet.ts b/src/Sheet.ts
 82index 0ea5470..8a42060 100644
 83--- a/src/Sheet.ts
 84+++ b/src/Sheet.ts
 85@@ -1,7 +1,7 @@
 86 /// <reference path="parser.d.ts"/>
 87 import { Parser } from "./Parser";
 88 import { Cell } from "./Cell"
 89-import { Errors } from "./Errors"
 90+import {DivZeroError, RefError, NameError} from "./Errors"
 91 import { Helpers } from "./Helpers";
 92 import { Formulas } from "./Formulas";
 93 
 94@@ -62,10 +62,7 @@ var Sheet = (function () {
 95     /**
 96      * Holds cells inside an object for quick access.
 97      */
 98-    public data: Object;
 99-    constructor() {
100-      this.data = {};
101-    }
102+    public data: Object = {};
103 
104     /**
105      * Gets the cell corresponding to the key. If the value is not defined, will return undefined.
106@@ -398,11 +395,12 @@ var Sheet = (function () {
107     mathMatch: function (type, number1, number2) {
108       var result;
109 
110+      // TODO: These should convert
111       number1 = helper.number(number1);
112       number2 = helper.number(number2);
113 
114       if (isNaN(number1) || isNaN(number2)) {
115-        throw Error('VALUE');
116+        throw Error('VALUE'); // TODO: we should catch and handle this when we convert the numbers...
117       }
118 
119       switch (type) {
120@@ -413,11 +411,14 @@ var Sheet = (function () {
121           result = number1 - number2;
122           break;
123         case '/':
124+          if (number2 === 0) {
125+            throw new DivZeroError("Evaluation caused divide by zero error.");
126+          }
127           result = number1 / number2;
128           if (result == Infinity) {
129-            throw Error('DIV_ZERO');
130+            throw new DivZeroError("Evaluation caused divide by zero error.");
131           } else if (isNaN(result)) {
132-            throw Error('VALUE');
133+            throw new DivZeroError("Evaluation caused divide by zero error.");
134           }
135           break;
136         case '*':
137@@ -438,7 +439,7 @@ var Sheet = (function () {
138         return Formulas.get(fn).apply(this, args);
139       }
140 
141-      throw Error('NAME');
142+      throw new NameError("Unknown function: '" + fn + "'.");
143     },
144 
145     callVariable: function (args) {
146@@ -452,7 +453,7 @@ var Sheet = (function () {
147         }
148       }
149 
150-      throw Error('NAME');
151+      throw new NameError("Unknown variable: '" + str + "'.");
152     },
153 
154     cellValue: function (cellId) {
155@@ -467,13 +468,13 @@ var Sheet = (function () {
156       // check references error
157       if (cell && cell.getDependencies()) {
158         if (cell.getDependencies().indexOf(cellId) !== -1) {
159-          throw Error('REF');
160+          throw new RefError("Reference does not exist.");
161         }
162       }
163 
164       // check if any error occurs
165       if (cell && cell.getError()) {
166-        throw Error(cell.getError());
167+        throw cell.getError()
168       }
169 
170       // return value if is set
171@@ -484,7 +485,7 @@ var Sheet = (function () {
172       }
173 
174       // cell is not available
175-      throw Error('NOT_AVAILABLE');
176+      return undefined;
177     },
178 
179     cellRangeValue: function (start: string, end: string) {
180@@ -533,18 +534,13 @@ var Sheet = (function () {
181       if (deps.indexOf(cellId) !== -1) {
182         result = null;
183         deps.forEach(function (id) {
184-          instance.matrix.getCell(id).setError(Errors.get('REF'));
185+          instance.matrix.getCell(id).setError(new RefError("Reference does not exist"));
186           instance.matrix.getCell(id).clearValue();
187         });
188-        throw Error('REF');
189+        throw new RefError("Reference does not exist.");
190       }
191     } catch (ex) {
192-      var message = Errors.get(ex.message);
193-      if (message) {
194-        error = message;
195-      } else {
196-        error = Errors.get('ERROR');
197-      }
198+      error = ex;
199     }
200 
201     return {
202diff --git a/tests/SheetFormulaTest.ts b/tests/SheetFormulaTest.ts
203index 6ad51de..c955148 100644
204--- a/tests/SheetFormulaTest.ts
205+++ b/tests/SheetFormulaTest.ts
206@@ -5,13 +5,22 @@ import {
207   assertEquals,
208   test
209 } from "./utils/Asserts";
210+import {DIV_ZERO_ERROR} from "../src/Errors";
211+
212+function assertFormulaEqualsError(formula: string, errorString: string) {
213+  var sheet  = new Sheet();
214+  sheet.setCell("A1", formula);
215+  var cell = sheet.getCell("A1");
216+  assertEquals(cell.getError().name, errorString);
217+  assertEquals(cell.getValue(), null);
218+}
219 
220 function assertFormulaEquals(formula: string, expectation: any) {
221   var sheet  = new Sheet();
222   sheet.setCell("A1", formula);
223   var cell = sheet.getCell("A1");
224-  assertEquals(null, cell.getError());
225-  assertEquals(expectation, cell.getValue());
226+  assertEquals(cell.getError(), null);
227+  assertEquals(cell.getValue(), expectation);
228 }
229 
230 function testFormulaToArray(formula: string, expectation: any) {
231@@ -418,3 +427,17 @@ test("Sheet TRUNC", function(){
232 test("Sheet XOR", function(){
233   assertFormulaEquals('=XOR(1, 1)', false);
234 });
235+
236+test("Sheet *", function(){
237+  assertFormulaEquals('= 10 * 10', 100);
238+  assertFormulaEquals('= 10 * 0', 0);
239+  assertFormulaEquals('= 10 * 0', 0);
240+  assertFormulaEquals('= 1 * 1', 1);
241+});
242+
243+test("Sheet /", function(){
244+  assertFormulaEquals('= 10 / 2', 5);
245+  assertFormulaEquals('= 10 / 1', 10);
246+  assertFormulaEquals('= 1 / 1', 1);
247+  assertFormulaEqualsError('= 10 / 0', DIV_ZERO_ERROR);
248+});
249diff --git a/tests/SheetTest.ts b/tests/SheetTest.ts
250index 7df93e2..d9b845e 100644
251--- a/tests/SheetTest.ts
252+++ b/tests/SheetTest.ts
253@@ -7,7 +7,8 @@ import {
254   test
255 } from "./utils/Asserts";
256 import {
257-  Errors
258+  REF_ERROR,
259+  NAME_ERROR
260 } from "../src/Errors";
261 
262 test("Sheet.setCell, Sheet.getCell", function(){
263@@ -97,11 +98,11 @@ test("Sheet REF error", function(){
264   sheet.setCell("B2", "=SUM(A1, B1)");
265   var B1 = sheet.getCell("B1");
266   assertEquals(null, B1.getValue());
267-  assertEquals(Errors.get("REF"), B1.getError());
268+  assertEquals(REF_ERROR, B1.getError().name);
269   assertArrayEquals(['A3', 'B2'], B1.getDependencies());
270   var B2 = sheet.getCell("B2");
271   assertEquals(null, B2.getValue());
272-  assertEquals(Errors.get("REF"), B2.getError());
273+  assertEquals(REF_ERROR, B2.getError().name);
274   assertArrayEquals(['A1', 'B1'], B2.getDependencies());
275 });
276 
277@@ -111,7 +112,7 @@ test("Sheet cell NAME error", function(){
278   sheet.setCell("A2", "=SUM(A1, NN)");
279   var A2 = sheet.getCell("A2");
280   assertEquals(null, A2.getValue());
281-  assertEquals(Errors.get("NAME"), A2.getError());
282+  assertEquals(NAME_ERROR, A2.getError().name);
283   assertArrayEquals(['A1'], A2.getDependencies());
284 });
285 
286@@ -121,7 +122,7 @@ test("Sheet unsupported formula NAME error", function(){
287   sheet.setCell("A2", "=BEN(A1)");
288   var A2 = sheet.getCell("A2");
289   assertEquals(null, A2.getValue());
290-  assertEquals(Errors.get("NAME"), A2.getError());
291+  assertEquals(NAME_ERROR, A2.getError().name);
292   assertArrayEquals(['A1'], A2.getDependencies());
293 });
294