spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Working towards implementing custom formulas and custom errors.
author
Ben Vogt <[email protected]>
date
2017-01-16 21:24:43
stats
3 file(s) changed, 100 insertions(+), 1 deletions(-)
files
src/Errors.ts
src/RawFormulas.ts
tests/FormulasTest.ts
  1diff --git a/src/Errors.ts b/src/Errors.ts
  2index 5f45e71..13238c9 100644
  3--- a/src/Errors.ts
  4+++ b/src/Errors.ts
  5@@ -1,3 +1,21 @@
  6+class CellError extends Error {
  7+  public message: string;
  8+  public text: string;
  9+  constructor(message: string, text: string) {
 10+    super(message);
 11+    this.message = message;
 12+    this.text = text;
 13+  }
 14+}
 15+
 16+var NULL_ERROR = "#NULL!";
 17+var DIV_ZERO_ERROR = "#DIV/0!";
 18+var VALUE_ERROR = "#VALUE!";
 19+var REF_ERROR = "#REF!";
 20+var NAME_ERROR = "#NAME!";
 21+var NUM_ERROR = "#NUM!";
 22+var NA_ERROR = "#N/A";
 23+
 24 var Errors = {
 25   errors: {
 26     'NULL': '#NULL',
 27@@ -14,6 +32,7 @@ var Errors = {
 28     '#NUM!': '#NUM!',
 29     'NOT_AVAILABLE': '#N/A!',
 30     '#N/A!': '#N/A!',
 31+    '#N/A': '#N/A',
 32     'ERROR': '#ERROR',
 33     '#ERROR': '#ERROR'
 34   },
 35@@ -26,5 +45,13 @@ var Errors = {
 36 };
 37 
 38 export {
 39-  Errors
 40+  Errors,
 41+  CellError,
 42+  DIV_ZERO_ERROR,
 43+  NULL_ERROR,
 44+  VALUE_ERROR,
 45+  REF_ERROR,
 46+  NAME_ERROR,
 47+  NUM_ERROR,
 48+  NA_ERROR
 49 }
 50\ No newline at end of file
 51diff --git a/src/RawFormulas.ts b/src/RawFormulas.ts
 52index 264b848..d550cfe 100644
 53--- a/src/RawFormulas.ts
 54+++ b/src/RawFormulas.ts
 55@@ -1,8 +1,54 @@
 56 /// <reference path="../node_modules/moment/moment.d.ts"/>
 57 import * as moment from "moment";
 58 import * as Formula from "formulajs"
 59+import { CellError } from "./Errors"
 60+import * as ERRORS from "./Errors"
 61+
 62+
 63+/**
 64+ * Checks to see if the arguments are of the correct length.
 65+ * @param args to check length of
 66+ * @param length expected length
 67+ */
 68+function checkArgumentsLength(args: any, length: number) {
 69+  if (args.length !== length) {
 70+    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
 71+  }
 72+}
 73+
 74+/**
 75+ * Converts any value to a number or throws an error if it cannot coerce it to the number type
 76+ * @param value to convert
 77+ * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
 78+ */
 79+function valueToNumber(value: any) : number {
 80+  if (typeof value === "number") {
 81+    return Math.abs(value);
 82+  } else if (typeof value === "string") {
 83+    if (value.indexOf(".") > -1) {
 84+      var fl = parseFloat(value);
 85+      if (isNaN(fl)) {
 86+        throw new CellError(ERRORS.VALUE_ERROR, "Function ____ parameter 1 expects number values, but is text and cannot be coerced to a number.");
 87+      }
 88+      return fl;
 89+    }
 90+    var fl = parseInt(value);
 91+    if (isNaN(fl)) {
 92+      throw new CellError(ERRORS.VALUE_ERROR, "Function ____ parameter 1 expects number values, but is text and cannot be coerced to a number.");
 93+    }
 94+    return fl;
 95+  } else if (typeof value === "boolean") {
 96+    return value ? 1 : 0;
 97+  }
 98+  return 0;
 99+}
100+
101+var ABS = function (value?) {
102+  checkArgumentsLength(arguments, 1);
103+  value = valueToNumber(value);
104+  return Math.abs(value);
105+};
106 
107-var ABS = Formula["ABS"];
108 var ACCRINT = function (issue, first, settlement, rate, par, frequency, basis) {
109   // Return error if either date is invalid
110   if (!moment(issue).isValid() || !moment(first).isValid() || !moment(settlement).isValid()) {
111diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
112index 2b468ef..bfb5d84 100644
113--- a/tests/FormulasTest.ts
114+++ b/tests/FormulasTest.ts
115@@ -9,10 +9,30 @@ import { ABS, ACCRINT, ACOS, ACOSH, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN, ATAN2
116     INT, ISEVEN, ISODD, LN, LOG, LOG10, MAX, MAXA, MEDIAN, MIN, MINA, MOD, NOT, TRUE, ODD, OR,
117     POWER, ROUND, ROUNDDOWN, ROUNDUP, SIN, SINH, SPLIT, SQRT, SQRTPI, SUM, SUMIF, SUMPRODUCT,
118     SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas"
119+import * as ERRORS from "../src/Errors"
120 import {assertEquals, assertEqualsDates, assertArrayEquals} from "./utils/Asserts"
121 
122+function catchAndAssertEquals(toExecute, expected) {
123+  try {
124+    toExecute();
125+  } catch (actualError) {
126+    if (actualError.message != expected) {
127+      console.log(expected, "not equal to", actualError.message);
128+    }
129+  }
130+}
131+
132 assertEquals(ABS(-10), 10);
133+assertEquals(ABS(-10.111), 10.111);
134 assertEquals(ABS(0), 0);
135+assertEquals(ABS(false), 0);
136+assertEquals(ABS("-44"), 44);
137+catchAndAssertEquals(function() {
138+  return ABS();
139+}, ERRORS.NA_ERROR);
140+catchAndAssertEquals(function() {
141+  return ABS("str");
142+}, ERRORS.VALUE_ERROR);
143 
144 // TODO: This formula doesn't work properly under some circumstances.
145 assertEquals(ACCRINT(DATE(2011, 1, 1), DATE(2011, 2, 1), DATE(2014, 7, 1), 0.1, 1000, 1, 0), 350);