spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
[Cell,Sheet,etc] work-in-progress on having all functions handle Cell objects
author
Ben Vogt <[email protected]>
date
2017-07-09 15:24:40
stats
6 file(s) changed, 97 insertions(+), 22 deletions(-)
files
src/Cell.ts
src/Sheet.ts
src/Utilities/TypeConverter.ts
tests/CellTest.ts
tests/SheetTest.ts
tests/Utils/Asserts.ts
  1diff --git a/src/Cell.ts b/src/Cell.ts
  2index cecd7e7..a5358a9 100644
  3--- a/src/Cell.ts
  4+++ b/src/Cell.ts
  5@@ -141,6 +141,22 @@ class Cell {
  6     return this.error;
  7   }
  8 
  9+  /**
 10+   * Easier way to check if this cell has an error.
 11+   * @returns {boolean}
 12+   */
 13+  hasError() : boolean {
 14+    return this.error !== null;
 15+  }
 16+
 17+  /**
 18+   * A cell is deemed blank if it contains no value, no error, and no typed value.
 19+   * @returns {boolean}
 20+   */
 21+  isBlank(): boolean {
 22+    return this.error === null && this.rawFormulaText === null && this.typedValue === null;
 23+  }
 24+
 25   /**
 26    * Returns the human-readable string representation of this cell, omitting some obvious fields.
 27    * @returns {string}
 28diff --git a/src/Sheet.ts b/src/Sheet.ts
 29index a299bd7..73768a3 100644
 30--- a/src/Sheet.ts
 31+++ b/src/Sheet.ts
 32@@ -77,12 +77,15 @@ var Sheet = (function () {
 33     public data: Object = {};
 34 
 35     /**
 36-     * Gets the cell corresponding to the key. If the value is not defined, will return undefined.
 37+     * Gets the cell corresponding to the key. If the value is undefined, will return blank cell..
 38      * @param key to look up cell
 39-     * @returns {Cell} to return, if it exists. Returns undefined if key not in matrix.
 40+     * @returns {Cell} to return, if it exists. Returns blank cell if key not in matrix.
 41      */
 42     getCell(key: string) : Cell {
 43-      return this.data[key];
 44+      if (key in this.data) {
 45+        return this.data[key];
 46+      }
 47+      return new Cell(key);
 48     }
 49 
 50     /**
 51@@ -463,7 +466,7 @@ var Sheet = (function () {
 52         cell = instance.matrix.getCell(cellId);
 53 
 54       // get value, defaulting to undefined
 55-      value = cell ? cell.getValue() : undefined;
 56+      value = cell.isBlank() ? undefined : cell.getValue();
 57       //update dependencies
 58       instance.matrix.getCell(origin).updateDependencies([cellId]);
 59       // check references error
 60@@ -474,19 +477,19 @@ var Sheet = (function () {
 61       }
 62 
 63       // check if any error occurs
 64-      if (cell && cell.getError()) {
 65+      if (!cell.isBlank() && cell.getError()) {
 66         throw cell.getError()
 67       }
 68 
 69+      if (cell.isBlank()) {
 70+        return cell;
 71+      }
 72+
 73       // return value if is set
 74       if (utils.isSet(value)) {
 75         var result = instance.helper.number(value);
 76-
 77         return !isNaN(result) ? result : value;
 78       }
 79-
 80-      // cell is not available
 81-      return undefined;
 82     },
 83 
 84     cellRangeValue: function (start: string, end: string) {
 85diff --git a/src/Utilities/TypeConverter.ts b/src/Utilities/TypeConverter.ts
 86index c0f0c69..ea479ef 100644
 87--- a/src/Utilities/TypeConverter.ts
 88+++ b/src/Utilities/TypeConverter.ts
 89@@ -7,6 +7,7 @@ import {
 90 import {
 91   DateRegExBuilder
 92 } from "./DateRegExBuilder";
 93+import {Cell} from "../Cell";
 94 
 95 const YEAR_MONTHDIG_DAY = DateRegExBuilder.DateRegExBuilder()
 96   .start()
 97@@ -426,7 +427,16 @@ class TypeConverter {
 98    * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
 99    */
100   public static valueToNumber(value : any) {
101-    if (typeof value === "number") {
102+    if (value instanceof Cell) {
103+      if (value.isBlank()) {
104+        return 0;
105+      } else {
106+        if (value.hasError()) {
107+          throw value.getError();
108+        }
109+        return value.getValue();
110+      }
111+    } else if (typeof value === "number") {
112       return value;
113     } else if (typeof value === "string") {
114       if (value === "") {
115diff --git a/tests/CellTest.ts b/tests/CellTest.ts
116index 911b1a8..5f0a2a5 100644
117--- a/tests/CellTest.ts
118+++ b/tests/CellTest.ts
119@@ -4,7 +4,7 @@ import {
120 import {
121   assertEquals,
122   assertArrayEquals,
123-  test
124+  test, assertIsNull
125 } from "./Utils/Asserts";
126 
127 test("Cell.constructor", function(){
128@@ -13,7 +13,7 @@ test("Cell.constructor", function(){
129   assertEquals(cell.getRow(), 0);
130   assertArrayEquals(cell.getDependencies(), []);
131   assertEquals(cell.getId(), "A1");
132-  assertEquals(cell.getFormula(), null);
133+  assertIsNull(cell.getFormula());
134   assertEquals(cell.hasFormula(), false);
135 });
136 
137@@ -30,3 +30,10 @@ test("Cell.setValue", function(){
138   v.setValue("100");
139   assertEquals("100", v.getValue());
140 });
141+
142+test("Cell.isBlank", function(){
143+  var v = new Cell("A1");
144+  assertIsNull(v.getValue());
145+  assertIsNull(v.getError());
146+  assertEquals(v.isBlank(), true);
147+});
148diff --git a/tests/SheetTest.ts b/tests/SheetTest.ts
149index fb4f419..baf08a1 100644
150--- a/tests/SheetTest.ts
151+++ b/tests/SheetTest.ts
152@@ -3,6 +3,7 @@ import {
153 } from "../src/Sheet";
154 import {
155   assertEquals,
156+  assertIsNull,
157   assertArrayEquals,
158   test
159 } from "./Utils/Asserts";
160@@ -21,12 +22,14 @@ test("Sheet.setCell, Sheet.getCell", function(){
161   assertEquals("A2", cell.getId());
162   assertEquals(1, cell.getRow());
163   assertEquals(0, cell.getColumn());
164-  assertEquals(null, cell.getError());
165+  assertIsNull(cell.getError());
166   assertArrayEquals([], cell.getDependencies());
167 
168-  // Test getCell, null value
169-  var nullCell = sheet.getCell("N1");
170-  assertEquals(null, nullCell);
171+  // Test getCell, blank cell value
172+  var blankCell = sheet.getCell("N1");
173+  assertEquals(true, blankCell.isBlank());
174+  assertIsNull(blankCell.getError());
175+  assertEquals(false, blankCell.hasFormula());
176 
177   // Test setCell, with formula
178   var sheet = new Sheet();
179@@ -39,7 +42,7 @@ test("Sheet.setCell, Sheet.getCell", function(){
180   var A5 = sheet.getCell("A5");
181   assertEquals(69.4, A5.getValue());
182   assertEquals(SUM_FORM.substr(1), A5.getFormula());
183-  assertEquals(null, cell.getError());
184+  assertIsNull(cell.getError());
185   assertArrayEquals(['A1', 'A2', 'A3', 'A4'], A5.getDependencies());
186 });
187 
188@@ -60,32 +63,32 @@ test("Sheet.load", function(){
189   var K1 = sheet.getCell("K1");
190   assertEquals(18, K1.getValue());
191   assertEquals(SUM_FORMULA.substr(1), K1.getFormula());
192-  assertEquals(null, K1.getError());
193+  assertIsNull(K1.getError());
194   assertArrayEquals(['A1', 'B1', 'C1', 'D1', 'H1'], K1.getDependencies());
195   var K2 = sheet.getCell("K2");
196   assertEquals(200, K2.getValue());
197   assertEquals(MAX_FORMULA.substr(1), K2.getFormula());
198-  assertEquals(null, K2.getError());
199+  assertIsNull(K2.getError());
200   assertArrayEquals(['A2', 'B2', 'C2', 'D2', 'E2', 'F2', 'G2', 'H2', 'I2', 'J2'], K2.getDependencies());
201   var K3 = sheet.getCell("K3");
202   assertEquals(-53, K3.getValue());
203   assertEquals(MIN_FORMULA.substr(1), K3.getFormula());
204-  assertEquals(null, K3.getError());
205+  assertIsNull(K3.getError());
206   assertArrayEquals(['A3', 'B3', 'C3', 'D3', 'E3', 'F3', 'G3', 'H3', 'I3', 'J3'], K3.getDependencies());
207   var K4 = sheet.getCell("K4");
208   assertEquals(30.4, K4.getValue());
209   assertEquals(AVERAGE_FORMULA.substr(1), K4.getFormula());
210-  assertEquals(null, K4.getError());
211+  assertIsNull(K4.getError());
212   assertArrayEquals(['A4', 'B4', 'C4', 'D4', 'E4', 'F4', 'G4', 'H4', 'I4', 'J4'], K4.getDependencies());
213   var K5 = sheet.getCell("K5");
214   assertEquals(0, K5.getValue());
215   assertEquals(SUM_IF_FORMULA.substr(1), K5.getFormula());
216-  assertEquals(null, K5.getError());
217+  assertIsNull(K5.getError());
218   assertArrayEquals(['A5', 'B5', 'C5', 'D5', 'E5', 'F5', 'G5', 'H5', 'I5', 'J5'], K5.getDependencies());
219   var K6 = sheet.getCell("K6");
220   assertEquals(195.4, K6.getValue());
221   assertEquals(SUM_REF_FORMULA.substr(1), K6.getFormula());
222-  assertEquals(null, K6.getError());
223+  assertIsNull(K6.getError());
224   assertArrayEquals(['K1', 'K2', 'K3', 'K4'], K6.getDependencies());
225 });
226 
227@@ -97,11 +100,11 @@ test("Sheet REF error", function(){
228   sheet.setCell("B1", "=SUM(A3, B2)");
229   sheet.setCell("B2", "=SUM(A1, B1)");
230   var B1 = sheet.getCell("B1");
231-  assertEquals(null, B1.getValue());
232+  assertIsNull(B1.getValue());
233   assertEquals(REF_ERROR, B1.getError().name);
234   assertArrayEquals(['A3', 'B2'], B1.getDependencies());
235   var B2 = sheet.getCell("B2");
236-  assertEquals(null, B2.getValue());
237+  assertIsNull(B2.getValue());
238   assertEquals(REF_ERROR, B2.getError().name);
239   assertArrayEquals(['A1', 'B1'], B2.getDependencies());
240 });
241@@ -111,7 +114,7 @@ test("Sheet cell NAME error", function(){
242   sheet.setCell("A1", "1");
243   sheet.setCell("A2", "=SUM(A1, NN)");
244   var A2 = sheet.getCell("A2");
245-  assertEquals(null, A2.getValue());
246+  assertIsNull(A2.getValue());
247   assertEquals(NAME_ERROR, A2.getError().name);
248   assertArrayEquals(['A1'], A2.getDependencies());
249 });
250@@ -121,7 +124,7 @@ test("Sheet unsupported formula NAME error", function(){
251   sheet.setCell("A1", "1");
252   sheet.setCell("A2", "=BEN(A1)");
253   var A2 = sheet.getCell("A2");
254-  assertEquals(null, A2.getValue());
255+  assertIsNull(A2.getValue());
256   assertEquals(NAME_ERROR, A2.getError().name);
257   assertArrayEquals(['A1'], A2.getDependencies());
258 });
259@@ -136,10 +139,22 @@ test("Sheet nested formulas", function(){
260   var A4 = sheet.getCell("A4");
261   assertEquals(99.8, A4.getValue());
262   assertEquals("SUM(A1:A3, MAX(A1, A3))", A4.getFormula());
263-  assertEquals(null, A4.getError());
264+  assertIsNull(A4.getError());
265   assertArrayEquals(['A1', 'A2', 'A3'], A4.getDependencies());
266 });
267 
268+test("Sheet cell range query", function(){
269+  var sheet  = new Sheet();
270+  sheet.setCell("A1", "1");
271+  sheet.setCell("A2", "1");
272+  sheet.setCell("A3", "1");
273+  sheet.setCell("A4", "1");
274+  sheet.setCell("A5", "1");
275+  sheet.setCell("N1", "=SUM(A1:A7)");
276+  var N1 = sheet.getCell("N1");
277+  assertArrayEquals(['A1', 'A2', 'A3', 'A4', 'A5', 'A6', 'A7'], N1.getDependencies());
278+});
279+
280 test("Sheet dependency calculation propagation", function(){
281   var sheet  = new Sheet();
282   sheet.setCell("A1", "1");
283diff --git a/tests/Utils/Asserts.ts b/tests/Utils/Asserts.ts
284index 3709262..46163c9 100644
285--- a/tests/Utils/Asserts.ts
286+++ b/tests/Utils/Asserts.ts
287@@ -10,6 +10,18 @@ function assertEquals(actual, expected) {
288   }
289 }
290 
291+/**
292+ * Asserts value is equal to null.
293+ * @param actual - value to test.
294+ */
295+function assertIsNull(actual) {
296+  if (null !== actual) {
297+    console.log("expected:", null, " actual:", actual);
298+    console.trace();
299+  }
300+}
301+
302+
303 /**
304  * Assert two arrays are equal using strict equality testing on individual items.
305  * @param actual value
306@@ -58,6 +70,7 @@ function test(description: string, toRun: Function) {
307 
308 
309 export {
310+  assertIsNull,
311   assertEquals,
312   assertArrayEquals,
313   catchAndAssertEquals,