spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← Commit log
commit
message
Refactoring RawFormulas into several files
author
Ben Vogt <[email protected]>
date
2017-01-22 17:51:34
stats
7 file(s) changed, 893 insertions(+), 885 deletions(-)
files
src/Formulas.ts
src/RawFormulas.ts
src/RawFormulas/Logical.ts
src/RawFormulas/Math.ts
src/RawFormulas/RawFormulas.ts
src/RawFormulas/Utils.ts
tests/FormulasTest.ts
   1diff --git a/src/Formulas.ts b/src/Formulas.ts
   2index 82a5211..cec9d8c 100644
   3--- a/src/Formulas.ts
   4+++ b/src/Formulas.ts
   5@@ -1,5 +1,5 @@
   6 import * as Formula from "formulajs"
   7-import * as RawFormulas from "./RawFormulas";
   8+import * as RawFormulas from "./RawFormulas/RawFormulas";
   9 
  10 const SUPPORTED_FORMULAS = [
  11   'ABS', 'ACCRINT', 'ACOS', 'ACOSH', 'ACOTH', 'AND', 'ARABIC', 'ASIN', 'ASINH', 'ATAN', 'ATAN2', 'ATANH', 'AVEDEV', 'AVERAGE', 'AVERAGEA', 'AVERAGEIF',
  12diff --git a/src/RawFormulas/Logical.ts b/src/RawFormulas/Logical.ts
  13new file mode 100644
  14index 0000000..72036de
  15--- /dev/null
  16+++ b/src/RawFormulas/Logical.ts
  17@@ -0,0 +1,99 @@
  18+import { checkArgumentsAtLeastLength, checkArgumentsLength, valueToString } from "./Utils"
  19+import { CellError } from "../Errors"
  20+import * as ERRORS from "../Errors"
  21+
  22+/**
  23+ * Returns true if all of the provided arguments are logically true, and false if any of the provided arguments are logically false.
  24+ * @param values At least one expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.
  25+ * @returns {boolean} if all values are logically true.
  26+ * @constructor
  27+ */
  28+var AND = function (...values) {
  29+  checkArgumentsAtLeastLength(values, 1);
  30+  var result = true;
  31+  for (var i = 0; i < values.length; i++) {
  32+    if (typeof values[i] === "string") {
  33+      throw new CellError(ERRORS.VALUE_ERROR, "AND expects boolean values. But '" + values[i] + "' is a text and cannot be coerced to a boolean.")
  34+    } else if (values[i] instanceof Array) {
  35+      if (!AND.apply(this, values[i])) {
  36+        result = false;
  37+        break;
  38+      }
  39+    } else if (!values[i]) {
  40+      result = false;
  41+      break;
  42+    }
  43+  }
  44+  return result;
  45+};
  46+
  47+/**
  48+ * Tests whether two strings are identical, returning true if they are.
  49+ * @param values[0] The first string to compare
  50+ * @param values[1] The second string to compare
  51+ * @returns {boolean}
  52+ * @constructor
  53+ */
  54+var EXACT = function (...values) {
  55+  checkArgumentsLength(values, 2);
  56+  var one = values[0];
  57+  var two = values[1];
  58+  if (one instanceof Array) {
  59+    if (one.length === 0) {
  60+      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
  61+    }
  62+  }
  63+  if (two instanceof Array) {
  64+    if (two.length === 0) {
  65+      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
  66+    }
  67+  }
  68+  one = valueToString(one);
  69+  two = valueToString(two);
  70+  return one === two;
  71+};
  72+
  73+/**
  74+ * Returns true.
  75+ * @returns {boolean} true boolean
  76+ * @constructor
  77+ */
  78+var TRUE = function () : boolean {
  79+  return true;
  80+};
  81+
  82+/**
  83+ * Returns the opposite of a logical value - NOT(TRUE) returns FALSE; NOT(FALSE) returns TRUE.
  84+ * @param values[0] An expression or reference to a cell holding an expression that represents some logical value.
  85+ * @returns {boolean} opposite of a logical value input
  86+ * @constructor
  87+ */
  88+var NOT = function (...values) : boolean {
  89+  checkArgumentsLength(values, 1);
  90+  var X = values[0];
  91+  if (typeof(X) === "boolean") {
  92+    return !X;
  93+  }
  94+  if (typeof(X) === "string") {
  95+    if (X === "") {
  96+      return true;
  97+    }
  98+    throw new CellError(ERRORS.VALUE_ERROR, "Function NOT parameter 1 expects boolean values. But '" + X + "' is a text and cannot be coerced to a boolean.")
  99+  }
 100+  if (typeof(X) === "number") {
 101+    return X === 0;
 102+  }
 103+  if (X instanceof Array) {
 104+    if (X.length === 0) {
 105+      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 106+    }
 107+    return NOT(X[0]);
 108+  }
 109+};
 110+
 111+export {
 112+  AND,
 113+  EXACT,
 114+  TRUE,
 115+  NOT
 116+}
 117\ No newline at end of file
 118diff --git a/src/RawFormulas.ts b/src/RawFormulas/Math.ts
 119similarity index 51%
 120rename from src/RawFormulas.ts
 121rename to src/RawFormulas/Math.ts
 122index 0b7b0c4..3dfeea7 100644
 123--- a/src/RawFormulas.ts
 124+++ b/src/RawFormulas/Math.ts
 125@@ -1,92 +1,6 @@
 126-/// <reference path="../node_modules/moment/moment.d.ts"/>
 127-import * as moment from "moment";
 128-import * as Formula from "formulajs"
 129-import { CellError } from "./Errors"
 130-import * as ERRORS from "./Errors"
 131-
 132-
 133-/**
 134- * Checks to see if the arguments are of the correct length.
 135- * @param args to check length of
 136- * @param length expected length
 137- */
 138-function checkArgumentsLength(args: any, length: number) {
 139-  if (args.length !== length) {
 140-    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
 141-  }
 142-}
 143-
 144-/**
 145- * Checks to see if the arguments are at least a certain length.
 146- * @param args to check length of
 147- * @param length expected length
 148- */
 149-function checkArgumentsAtLeastLength(args: any, length: number) {
 150-  if (args.length < length) {
 151-    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
 152-  }
 153-}
 154-
 155-/**
 156- * Filter out all strings from an array.
 157- * @param arr to filter
 158- * @returns {Array} filtered array
 159- */
 160-function filterOutStringValues(arr: Array<any>) : Array<any> {
 161-  var toReturn = [];
 162-  for (var i = 0; i < arr.length; i++) {
 163-    if (typeof arr[i] !== "string") {
 164-      toReturn.push(arr[i]);
 165-    }
 166-  }
 167-  return toReturn;
 168-}
 169-
 170-/**
 171- * Convert a value to string.
 172- * @param value of any type, including array. array cannot be empty.
 173- * @returns {string} string representation of value
 174- */
 175-function valueToString(value: any) : string {
 176-  if (typeof value === "number") {
 177-    return value.toString();
 178-  } else if (typeof value === "string") {
 179-    return value;
 180-  } else if (typeof value === "boolean") {
 181-    return value ? "TRUE" : "FALSE";
 182-  } else if (value instanceof Array) {
 183-    return valueToString(value[0]);
 184-  }
 185-}
 186-
 187-
 188-/**
 189- * Converts any value to a number or throws an error if it cannot coerce it to the number type
 190- * @param value to convert
 191- * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
 192- */
 193-function valueToNumber(value: any) : number {
 194-  if (typeof value === "number") {
 195-    return value;
 196-  } else if (typeof value === "string") {
 197-    if (value.indexOf(".") > -1) {
 198-      var fl = parseFloat(value);
 199-      if (isNaN(fl)) {
 200-        throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
 201-      }
 202-      return fl;
 203-    }
 204-    var fl = parseInt(value);
 205-    if (isNaN(fl)) {
 206-      throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
 207-    }
 208-    return fl;
 209-  } else if (typeof value === "boolean") {
 210-    return value ? 1 : 0;
 211-  }
 212-  return 0;
 213-}
 214-
 215+import { checkArgumentsLength, checkArgumentsAtLeastLength, valueToNumber, filterOutStringValues} from "./Utils"
 216+import { CellError } from "../Errors"
 217+import * as ERRORS from "../Errors"
 218 
 219 /**
 220  * Returns the absolute value of a number.
 221@@ -100,63 +14,6 @@ var ABS = function (value?) {
 222   return Math.abs(value);
 223 };
 224 
 225-var ACCRINT = function (issue, first, settlement, rate, par, frequency, basis) {
 226-  // Return error if either date is invalid
 227-  if (!moment(issue).isValid() || !moment(first).isValid() || !moment(settlement).isValid()) {
 228-    return '#VALUE!';
 229-  }
 230-
 231-  // Set default values
 232-  par = (typeof par === 'undefined') ? 0 : par;
 233-  basis = (typeof basis === 'undefined') ? 0 : basis;
 234-
 235-  // Return error if either rate or par are lower than or equal to zero
 236-  if (rate <= 0 || par <= 0) {
 237-    return '#NUM!';
 238-  }
 239-
 240-  // Return error if frequency is neither 1, 2, or 4
 241-  if ([1, 2, 4].indexOf(frequency) === -1) {
 242-    return '#NUM!';
 243-  }
 244-
 245-  // Return error if basis is neither 0, 1, 2, 3, or 4
 246-  if ([0, 1, 2, 3, 4].indexOf(basis) === -1) {
 247-    return '#NUM!';
 248-  }
 249-
 250-  // Return error if issue greater than or equal to settlement
 251-  if (moment(issue).diff(moment(settlement)) >= 0) {
 252-    return '#NUM!';
 253-  }
 254-
 255-  // Compute accrued interest
 256-  var factor : any = 0;
 257-  switch (basis) {
 258-    case 0:
 259-      // US (NASD) 30/360
 260-      factor = YEARFRAC(issue, settlement, basis);
 261-      break;
 262-    case 1:
 263-      // Actual/actual
 264-      factor = YEARFRAC(issue, settlement, basis);
 265-      break;
 266-    case 2:
 267-      // Actual/360
 268-      factor = YEARFRAC(issue, settlement, basis);
 269-      break;
 270-    case 3:
 271-      // Actual/365
 272-      factor = YEARFRAC(issue, settlement, basis);
 273-      break;
 274-    case 4:
 275-      // European 30/360
 276-      factor = YEARFRAC(issue, settlement, basis);
 277-      break;
 278-  }
 279-  return par * rate * factor;
 280-};
 281-
 282 /**
 283  * Returns the inverse cosine of a value, in radians.
 284  * @param value The value for which to calculate the inverse cosine. Must be between -1 and 1, inclusive.
 285@@ -204,33 +61,6 @@ var ACOTH = function (value?) {
 286   return 0.5 * Math.log((value + 1) / (value - 1));
 287 };
 288 
 289-
 290-/**
 291- * Returns true if all of the provided arguments are logically true, and false if any of the provided arguments are logically false.
 292- * @param values At least one expression or reference to a cell containing an expression that represents some logical value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.
 293- * @returns {boolean} if all values are logically true.
 294- * @constructor
 295- */
 296-var AND = function (...values) {
 297-  checkArgumentsAtLeastLength(values, 1);
 298-  var result = true;
 299-  for (var i = 0; i < values.length; i++) {
 300-    if (typeof values[i] === "string") {
 301-      throw new CellError(ERRORS.VALUE_ERROR, "AND expects boolean values. But '" + values[i] + "' is a text and cannot be coerced to a boolean.")
 302-    } else if (values[i] instanceof Array) {
 303-      if (!AND.apply(this, values[i])) {
 304-        result = false;
 305-        break;
 306-      }
 307-    } else if (!values[i]) {
 308-      result = false;
 309-      break;
 310-    }
 311-  }
 312-  return result;
 313-};
 314-
 315-
 316 /**
 317  * Computes the value of a Roman numeral.
 318  * @param text The Roman numeral to format, whose value must be between 1 and 3999, inclusive.
 319@@ -346,8 +176,6 @@ var ATANH = function (value?) : number {
 320 };
 321 
 322 
 323-var AVEDEV = Formula["AVEDEV"];
 324-
 325 /**
 326  * Returns the numerical average value in a dataset, ignoring text.
 327  * @param values The values or ranges to consider when calculating the average value.
 328@@ -372,85 +200,7 @@ var AVERAGE = function (...values) : number {
 329     }
 330   }
 331   return result / count;
 332-
 333-};
 334-var AVERAGEA = Formula["AVERAGEA"];
 335-var AVERAGEIF = Formula["AVERAGEIF"];
 336-var BASE = Formula["BASE"];
 337-var BIN2DEC = Formula["BIN2DEC"];
 338-var BESSELI = Formula["BESSELI"];
 339-var BESSELJ = Formula["BESSELJ"];
 340-var BESSELK = Formula["BESSELK"];
 341-var BESSELY = Formula["BESSELY"];
 342-var BETADIST = Formula["BETADIST"];
 343-var BETAINV = Formula["BETAINV"];
 344-var BITAND = Formula["BITAND"];
 345-var BITLSHIFT = Formula["BITLSHIFT"];
 346-var BITOR = Formula["BITOR"];
 347-var BITRSHIFT = Formula["BITRSHIFT"];
 348-var BITXOR = Formula["BITXOR"];
 349-var BIN2HEX = Formula["BIN2HEX"];
 350-var BIN2OCT = Formula["BIN2OCT"];
 351-var DECIMAL = Formula["DECIMAL"];
 352-var CEILING = Formula["CEILING"];
 353-var CEILINGMATH = Formula["CEILINGMATH"];
 354-var CEILINGPRECISE = Formula["CEILINGPRECISE"];
 355-var CHAR = Formula["CHAR"];
 356-var CODE = Formula["CODE"];
 357-var COMBIN = Formula["COMBIN"];
 358-var COMBINA = Formula["COMBINA"];
 359-var COMPLEX = Formula["COMPLEX"];
 360-var CONCATENATE = Formula["CONCATENATE"];
 361-var CONVERT = Formula["CONVERT"];
 362-var CORREL = Formula["CORREL"];
 363-var COS = Formula["COS"];
 364-var PI = function () {
 365-  return Math.PI;
 366-};
 367-var COSH = Formula["COSH"];
 368-var COT = Formula["COT"];
 369-var COTH = Formula["COTH"];
 370-var COUNT = Formula["COUNT"];
 371-var COUNTA = Formula["COUNTA"];
 372-var COUNTIF = Formula["COUNTIF"];
 373-var COUNTIFS = Formula["COUNTIFS"];
 374-var COUNTIN = Formula["COUNTIN"];
 375-var COUNTUNIQUE = Formula["COUNTUNIQUE"];
 376-var COVARIANCEP = Formula["COVARIANCEP"];
 377-var COVARIANCES = Formula["COVARIANCES"];
 378-var CSC = Formula["CSC"];
 379-var CSCH = Formula["CSCH"];
 380-var CUMIPMT = Formula["CUMIPMT"];
 381-var CUMPRINC = Formula["CUMPRINC"];
 382-var DATE = Formula["DATE"];
 383-var DATEVALUE = function (dateString: string) : Date {
 384-  return new Date(dateString);
 385-};
 386-var DAY = Formula["DAY"];
 387-var DAYS = Formula["DAYS"];
 388-var DAYS360 = Formula["DAYS360"];
 389-var DB = Formula["DB"];
 390-var DDB = Formula["DDB"];
 391-var DEC2BIN = Formula["DEC2BIN"];
 392-var DEC2HEX = Formula["DEC2HEX"];
 393-var DEC2OCT = Formula["DEC2OCT"];
 394-var DEGREES = Formula["DEGREES"];
 395-var DELTA = Formula["DELTA"];
 396-var DEVSQ = Formula["DEVSQ"];
 397-var DOLLAR = Formula["DOLLAR"];
 398-var DOLLARDE = Formula["DOLLARDE"];
 399-var DOLLARFR = Formula["DOLLARFR"];
 400-var EDATE = function (start_date: Date, months) {
 401-  return moment(start_date).add(months, 'months').toDate();
 402-};
 403-var EFFECT = Formula["EFFECT"];
 404-var EOMONTH = function (start_date, months) {
 405-  var edate = moment(start_date).add(months, 'months');
 406-  return new Date(edate.year(), edate.month(), edate.daysInMonth());
 407 };
 408-var ERF = Formula["ERF"];
 409-var ERFC = Formula["ERFC"];
 410-
 411 
 412 /**
 413  * Rounds a number up to the nearest even integer.
 414@@ -470,51 +220,6 @@ var EVEN = function (...values) : number {
 415   return X % 2 === 1 ? X + 1 : X;
 416 };
 417 
 418-
 419-/**
 420- * Tests whether two strings are identical, returning true if they are.
 421- * @param values[0] The first string to compare
 422- * @param values[1] The second string to compare
 423- * @returns {boolean}
 424- * @constructor
 425- */
 426-var EXACT = function (...values) {
 427-  checkArgumentsLength(values, 2);
 428-  var one = values[0];
 429-  var two = values[1];
 430-  if (one instanceof Array) {
 431-    if (one.length === 0) {
 432-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 433-    }
 434-  }
 435-  if (two instanceof Array) {
 436-    if (two.length === 0) {
 437-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 438-    }
 439-  }
 440-  one = valueToString(one);
 441-  two = valueToString(two);
 442-  return one === two;
 443-};
 444-
 445-
 446-
 447-var EXPONDIST = Formula["EXPONDIST"];
 448-var FALSE = Formula["FALSE"];
 449-var __COMPLEX = {
 450-  "F.DIST": Formula["FDIST"],
 451-  "F.INV": Formula["FINV"]
 452-};
 453-var FISHER = Formula["FISHER"];
 454-var FISHERINV = Formula["FISHERINV"];
 455-var IF = Formula["IF"];
 456-var INT = Formula["INT"];
 457-var ISEVEN = Formula["ISEVEN"];
 458-var ISODD = Formula["ISODD"];
 459-var LN = Formula["LN"];
 460-var LOG = Formula["LOG"];
 461-var LOG10 = Formula["LOG10"];
 462-
 463 /**
 464  * Returns the maximum value in a numeric dataset.
 465  * @param values The values or range(s) to consider when calculating the maximum value.
 466@@ -540,7 +245,6 @@ var MAX = function (...values) {
 467   return maxSoFar;
 468 };
 469 
 470-
 471 /**
 472  * Returns the maximum numeric value in a dataset.
 473  * @param values The value(s) or range(s) to consider when calculating the maximum value.
 474@@ -594,7 +298,6 @@ var MEDIAN = function (...values) : number {
 475   }
 476 };
 477 
 478-
 479 /**
 480  * Returns the minimum value in a numeric dataset.
 481  * @param values The value(s) or range(s) to consider when calculating the minimum value.
 482@@ -650,46 +353,6 @@ var MOD = function (...values) : number {
 483 };
 484 
 485 
 486-/**
 487- * Returns true.
 488- * @returns {boolean} true boolean
 489- * @constructor
 490- */
 491-var TRUE = function () : boolean {
 492-  return true;
 493-};
 494-
 495-
 496-/**
 497- * Returns the opposite of a logical value - NOT(TRUE) returns FALSE; NOT(FALSE) returns TRUE.
 498- * @param values[0] An expression or reference to a cell holding an expression that represents some logical value.
 499- * @returns {boolean} opposite of a logical value input
 500- * @constructor
 501- */
 502-var NOT = function (...values) : boolean {
 503-  checkArgumentsLength(values, 1);
 504-  var X = values[0];
 505-  if (typeof(X) === "boolean") {
 506-    return !X;
 507-  }
 508-  if (typeof(X) === "string") {
 509-    if (X === "") {
 510-      return true;
 511-    }
 512-    throw new CellError(ERRORS.VALUE_ERROR, "Function NOT parameter 1 expects boolean values. But '" + X + "' is a text and cannot be coerced to a boolean.")
 513-  }
 514-  if (typeof(X) === "number") {
 515-    return X === 0;
 516-  }
 517-  if (X instanceof Array) {
 518-    if (X.length === 0) {
 519-      throw new CellError(ERRORS.REF_ERROR, "Reference does not exist.");
 520-    }
 521-    return NOT(X[0]);
 522-  }
 523-};
 524-
 525-
 526 /**
 527  * Rounds a number up to the nearest odd integer.
 528  * @param values[0] The value to round to the next greatest odd number.
 529@@ -708,20 +371,6 @@ var ODD = function (...values) : number {
 530   return X % 2 === 1 ? X : X + 1;
 531 };
 532 
 533-
 534-var OR = Formula["OR"];
 535-var POWER = Formula["POWER"];
 536-var ROUND = Formula["ROUND"];
 537-var ROUNDDOWN = Formula["ROUNDDOWN"];
 538-var ROUNDUP = Formula["ROUNDUP"];
 539-var SIN = function (rad) {
 540-  return rad === Math.PI ? 0 : Math.sin(rad);
 541-};
 542-var SINH = Formula["SINH"];
 543-var SPLIT = Formula["SPLIT"];
 544-var SQRT = Formula["SQRT"];
 545-var SQRTPI = Formula["SQRTPI"];
 546-
 547 /**
 548  * Returns the sum of a series of numbers and/or cells.
 549  * @param values The first number or range to add together.
 550@@ -740,144 +389,26 @@ var SUM = function (...values) : number {
 551   }
 552   return result;
 553 };
 554-var SUMIF = Formula["SUMIF"];
 555-var SUMPRODUCT = Formula["SUMPRODUCT"];
 556-var SUMSQ = Formula["SUMSQ"];
 557-var SUMX2MY2 = Formula["SUMX2MY2"];
 558-var SUMX2PY2 = Formula["SUMX2PY2"];
 559-var TAN = function (rad) {
 560-  return rad === Math.PI ? 0 : Math.tan(rad);
 561-};
 562-var TANH = Formula["TANH"];
 563-var TRUNC = Formula["TRUNC"];
 564-var XOR = Formula["XOR"];
 565-var YEARFRAC = Formula["YEARFRAC"];
 566 
 567 export {
 568-  __COMPLEX,
 569-
 570   ABS,
 571   ACOS,
 572-  ACCRINT,
 573   ACOSH,
 574   ACOTH,
 575-  AND,
 576   ARABIC,
 577   ASIN,
 578   ASINH,
 579   ATAN,
 580   ATAN2,
 581   ATANH,
 582-  AVEDEV,
 583   AVERAGE,
 584-  AVERAGEA,
 585-  AVERAGEIF,
 586-  BASE,
 587-  BIN2DEC,
 588-  BESSELI,
 589-  BESSELJ,
 590-  BESSELK,
 591-  BESSELY,
 592-  BETADIST,
 593-  BETAINV,
 594-  BITAND,
 595-  BITLSHIFT,
 596-  BITOR,
 597-  BITRSHIFT,
 598-  BITXOR,
 599-  BIN2HEX,
 600-  BIN2OCT,
 601-  DECIMAL,
 602-  CEILING,
 603-  CEILINGMATH,
 604-  CEILINGPRECISE,
 605-  CHAR,
 606-  CODE,
 607-  COMBIN,
 608-  COMBINA,
 609-  COMPLEX,
 610-  CONCATENATE,
 611-  CONVERT,
 612-  CORREL,
 613-  COS,
 614-  PI,
 615-  COSH,
 616-  COT,
 617-  COTH,
 618-  COUNT,
 619-  COUNTA,
 620-  COUNTIF,
 621-  COUNTIFS,
 622-  COUNTIN,
 623-  COUNTUNIQUE,
 624-  COVARIANCEP,
 625-  COVARIANCES,
 626-  CSC,
 627-  CSCH,
 628-  CUMIPMT,
 629-  CUMPRINC,
 630-  DATE,
 631-  DATEVALUE,
 632-  DAY,
 633-  DAYS,
 634-  DAYS360,
 635-  DB,
 636-  DDB,
 637-  DEC2BIN,
 638-  DEC2HEX,
 639-  DEC2OCT,
 640-  DEGREES,
 641-  DELTA,
 642-  DEVSQ,
 643-  DOLLAR,
 644-  DOLLARDE,
 645-  DOLLARFR,
 646-  EDATE,
 647-  EFFECT,
 648-  EOMONTH,
 649-  ERF,
 650-  ERFC,
 651   EVEN,
 652-  EXACT,
 653-  EXPONDIST,
 654-  FALSE,
 655-  FISHER,
 656-  FISHERINV,
 657-  IF,
 658-  INT,
 659-  ISEVEN,
 660-  ISODD,
 661-  LN,
 662-  LOG,
 663-  LOG10,
 664   MAX,
 665   MAXA,
 666   MEDIAN,
 667   MIN,
 668   MINA,
 669   MOD,
 670-  TRUE,
 671-  NOT,
 672   ODD,
 673-  OR,
 674-  POWER,
 675-  ROUND,
 676-  ROUNDDOWN,
 677-  ROUNDUP,
 678-  SIN,
 679-  SINH,
 680-  SPLIT,
 681-  SQRT,
 682-  SQRTPI,
 683-  SUM,
 684-  SUMIF,
 685-  SUMPRODUCT,
 686-  SUMSQ,
 687-  SUMX2MY2,
 688-  SUMX2PY2,
 689-  TAN,
 690-  TANH,
 691-  TRUNC,
 692-  XOR,
 693-  YEARFRAC
 694+  SUM
 695 }
 696\ No newline at end of file
 697diff --git a/src/RawFormulas/RawFormulas.ts b/src/RawFormulas/RawFormulas.ts
 698new file mode 100644
 699index 0000000..cb1f3aa
 700--- /dev/null
 701+++ b/src/RawFormulas/RawFormulas.ts
 702@@ -0,0 +1,285 @@
 703+/// <reference path="../../node_modules/moment/moment.d.ts"/>
 704+import * as moment from "moment";
 705+import * as Formula from "formulajs"
 706+import {
 707+  ABS,
 708+  ACOS,
 709+  ACOSH,
 710+  ACOTH,
 711+  ARABIC,
 712+  ASIN,
 713+  ASINH,
 714+  ATAN,
 715+  ATAN2,
 716+  ATANH,
 717+  AVERAGE,
 718+  EVEN,
 719+  MAX,
 720+  MAXA,
 721+  MEDIAN,
 722+  MIN,
 723+  MINA,
 724+  MOD,
 725+  ODD,
 726+  SUM
 727+} from "./Math";
 728+import {
 729+  AND,
 730+  EXACT,
 731+  TRUE,
 732+  NOT
 733+} from "./Logical"
 734+
 735+var ACCRINT = Formula["ACCRINT"];
 736+var AVEDEV = Formula["AVEDEV"];
 737+var AVERAGEA = Formula["AVERAGEA"];
 738+var AVERAGEIF = Formula["AVERAGEIF"];
 739+var BASE = Formula["BASE"];
 740+var BIN2DEC = Formula["BIN2DEC"];
 741+var BESSELI = Formula["BESSELI"];
 742+var BESSELJ = Formula["BESSELJ"];
 743+var BESSELK = Formula["BESSELK"];
 744+var BESSELY = Formula["BESSELY"];
 745+var BETADIST = Formula["BETADIST"];
 746+var BETAINV = Formula["BETAINV"];
 747+var BITAND = Formula["BITAND"];
 748+var BITLSHIFT = Formula["BITLSHIFT"];
 749+var BITOR = Formula["BITOR"];
 750+var BITRSHIFT = Formula["BITRSHIFT"];
 751+var BITXOR = Formula["BITXOR"];
 752+var BIN2HEX = Formula["BIN2HEX"];
 753+var BIN2OCT = Formula["BIN2OCT"];
 754+var DECIMAL = Formula["DECIMAL"];
 755+var CEILING = Formula["CEILING"];
 756+var CEILINGMATH = Formula["CEILINGMATH"];
 757+var CEILINGPRECISE = Formula["CEILINGPRECISE"];
 758+var CHAR = Formula["CHAR"];
 759+var CODE = Formula["CODE"];
 760+var COMBIN = Formula["COMBIN"];
 761+var COMBINA = Formula["COMBINA"];
 762+var COMPLEX = Formula["COMPLEX"];
 763+var CONCATENATE = Formula["CONCATENATE"];
 764+var CONVERT = Formula["CONVERT"];
 765+var CORREL = Formula["CORREL"];
 766+var COS = Formula["COS"];
 767+var PI = function () {
 768+  return Math.PI;
 769+};
 770+var COSH = Formula["COSH"];
 771+var COT = Formula["COT"];
 772+var COTH = Formula["COTH"];
 773+var COUNT = Formula["COUNT"];
 774+var COUNTA = Formula["COUNTA"];
 775+var COUNTIF = Formula["COUNTIF"];
 776+var COUNTIFS = Formula["COUNTIFS"];
 777+var COUNTIN = Formula["COUNTIN"];
 778+var COUNTUNIQUE = Formula["COUNTUNIQUE"];
 779+var COVARIANCEP = Formula["COVARIANCEP"];
 780+var COVARIANCES = Formula["COVARIANCES"];
 781+var CSC = Formula["CSC"];
 782+var CSCH = Formula["CSCH"];
 783+var CUMIPMT = Formula["CUMIPMT"];
 784+var CUMPRINC = Formula["CUMPRINC"];
 785+var DATE = Formula["DATE"];
 786+var DATEVALUE = function (dateString: string) : Date {
 787+  return new Date(dateString);
 788+};
 789+var DAY = Formula["DAY"];
 790+var DAYS = Formula["DAYS"];
 791+var DAYS360 = Formula["DAYS360"];
 792+var DB = Formula["DB"];
 793+var DDB = Formula["DDB"];
 794+var DEC2BIN = Formula["DEC2BIN"];
 795+var DEC2HEX = Formula["DEC2HEX"];
 796+var DEC2OCT = Formula["DEC2OCT"];
 797+var DEGREES = Formula["DEGREES"];
 798+var DELTA = Formula["DELTA"];
 799+var DEVSQ = Formula["DEVSQ"];
 800+var DOLLAR = Formula["DOLLAR"];
 801+var DOLLARDE = Formula["DOLLARDE"];
 802+var DOLLARFR = Formula["DOLLARFR"];
 803+var EDATE = function (start_date: Date, months) {
 804+  return moment(start_date).add(months, 'months').toDate();
 805+};
 806+var EFFECT = Formula["EFFECT"];
 807+var EOMONTH = function (start_date, months) {
 808+  var edate = moment(start_date).add(months, 'months');
 809+  return new Date(edate.year(), edate.month(), edate.daysInMonth());
 810+};
 811+var ERF = Formula["ERF"];
 812+var ERFC = Formula["ERFC"];
 813+
 814+
 815+
 816+
 817+var EXPONDIST = Formula["EXPONDIST"];
 818+var FALSE = Formula["FALSE"];
 819+var __COMPLEX = {
 820+  "F.DIST": Formula["FDIST"],
 821+  "F.INV": Formula["FINV"]
 822+};
 823+var FISHER = Formula["FISHER"];
 824+var FISHERINV = Formula["FISHERINV"];
 825+var IF = Formula["IF"];
 826+var INT = Formula["INT"];
 827+var ISEVEN = Formula["ISEVEN"];
 828+var ISODD = Formula["ISODD"];
 829+var LN = Formula["LN"];
 830+var LOG = Formula["LOG"];
 831+var LOG10 = Formula["LOG10"];
 832+
 833+
 834+
 835+var OR = Formula["OR"];
 836+var POWER = Formula["POWER"];
 837+var ROUND = Formula["ROUND"];
 838+var ROUNDDOWN = Formula["ROUNDDOWN"];
 839+var ROUNDUP = Formula["ROUNDUP"];
 840+var SIN = function (rad) {
 841+  return rad === Math.PI ? 0 : Math.sin(rad);
 842+};
 843+var SINH = Formula["SINH"];
 844+var SPLIT = Formula["SPLIT"];
 845+var SQRT = Formula["SQRT"];
 846+var SQRTPI = Formula["SQRTPI"];
 847+var SUMIF = Formula["SUMIF"];
 848+var SUMPRODUCT = Formula["SUMPRODUCT"];
 849+var SUMSQ = Formula["SUMSQ"];
 850+var SUMX2MY2 = Formula["SUMX2MY2"];
 851+var SUMX2PY2 = Formula["SUMX2PY2"];
 852+var TAN = function (rad) {
 853+  return rad === Math.PI ? 0 : Math.tan(rad);
 854+};
 855+var TANH = Formula["TANH"];
 856+var TRUNC = Formula["TRUNC"];
 857+var XOR = Formula["XOR"];
 858+var YEARFRAC = Formula["YEARFRAC"];
 859+
 860+export {
 861+  __COMPLEX,
 862+
 863+  ABS,
 864+  ACOS,
 865+  ACCRINT,
 866+  ACOSH,
 867+  ACOTH,
 868+  AND,
 869+  ARABIC,
 870+  ASIN,
 871+  ASINH,
 872+  ATAN,
 873+  ATAN2,
 874+  ATANH,
 875+  AVEDEV,
 876+  AVERAGE,
 877+  AVERAGEA,
 878+  AVERAGEIF,
 879+  BASE,
 880+  BIN2DEC,
 881+  BESSELI,
 882+  BESSELJ,
 883+  BESSELK,
 884+  BESSELY,
 885+  BETADIST,
 886+  BETAINV,
 887+  BITAND,
 888+  BITLSHIFT,
 889+  BITOR,
 890+  BITRSHIFT,
 891+  BITXOR,
 892+  BIN2HEX,
 893+  BIN2OCT,
 894+  DECIMAL,
 895+  CEILING,
 896+  CEILINGMATH,
 897+  CEILINGPRECISE,
 898+  CHAR,
 899+  CODE,
 900+  COMBIN,
 901+  COMBINA,
 902+  COMPLEX,
 903+  CONCATENATE,
 904+  CONVERT,
 905+  CORREL,
 906+  COS,
 907+  PI,
 908+  COSH,
 909+  COT,
 910+  COTH,
 911+  COUNT,
 912+  COUNTA,
 913+  COUNTIF,
 914+  COUNTIFS,
 915+  COUNTIN,
 916+  COUNTUNIQUE,
 917+  COVARIANCEP,
 918+  COVARIANCES,
 919+  CSC,
 920+  CSCH,
 921+  CUMIPMT,
 922+  CUMPRINC,
 923+  DATE,
 924+  DATEVALUE,
 925+  DAY,
 926+  DAYS,
 927+  DAYS360,
 928+  DB,
 929+  DDB,
 930+  DEC2BIN,
 931+  DEC2HEX,
 932+  DEC2OCT,
 933+  DEGREES,
 934+  DELTA,
 935+  DEVSQ,
 936+  DOLLAR,
 937+  DOLLARDE,
 938+  DOLLARFR,
 939+  EDATE,
 940+  EFFECT,
 941+  EOMONTH,
 942+  ERF,
 943+  ERFC,
 944+  EVEN,
 945+  EXACT,
 946+  EXPONDIST,
 947+  FALSE,
 948+  FISHER,
 949+  FISHERINV,
 950+  IF,
 951+  INT,
 952+  ISEVEN,
 953+  ISODD,
 954+  LN,
 955+  LOG,
 956+  LOG10,
 957+  MAX,
 958+  MAXA,
 959+  MEDIAN,
 960+  MIN,
 961+  MINA,
 962+  MOD,
 963+  TRUE,
 964+  NOT,
 965+  ODD,
 966+  OR,
 967+  POWER,
 968+  ROUND,
 969+  ROUNDDOWN,
 970+  ROUNDUP,
 971+  SIN,
 972+  SINH,
 973+  SPLIT,
 974+  SQRT,
 975+  SQRTPI,
 976+  SUM,
 977+  SUMIF,
 978+  SUMPRODUCT,
 979+  SUMSQ,
 980+  SUMX2MY2,
 981+  SUMX2PY2,
 982+  TAN,
 983+  TANH,
 984+  TRUNC,
 985+  XOR,
 986+  YEARFRAC
 987+}
 988\ No newline at end of file
 989diff --git a/src/RawFormulas/Utils.ts b/src/RawFormulas/Utils.ts
 990new file mode 100644
 991index 0000000..b21e770
 992--- /dev/null
 993+++ b/src/RawFormulas/Utils.ts
 994@@ -0,0 +1,93 @@
 995+import { CellError } from "../Errors"
 996+import * as ERRORS from "../Errors"
 997+
 998+/**
 999+ * Checks to see if the arguments are of the correct length.
1000+ * @param args to check length of
1001+ * @param length expected length
1002+ */
1003+function checkArgumentsLength(args: any, length: number) {
1004+  if (args.length !== length) {
1005+    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
1006+  }
1007+}
1008+
1009+/**
1010+ * Checks to see if the arguments are at least a certain length.
1011+ * @param args to check length of
1012+ * @param length expected length
1013+ */
1014+function checkArgumentsAtLeastLength(args: any, length: number) {
1015+  if (args.length < length) {
1016+    throw new CellError(ERRORS.NA_ERROR, "Wrong number of arguments to ABS. Expected 1 arguments, but got " + args.length + " arguments.");
1017+  }
1018+}
1019+
1020+/**
1021+ * Filter out all strings from an array.
1022+ * @param arr to filter
1023+ * @returns {Array} filtered array
1024+ */
1025+function filterOutStringValues(arr: Array<any>) : Array<any> {
1026+  var toReturn = [];
1027+  for (var i = 0; i < arr.length; i++) {
1028+    if (typeof arr[i] !== "string") {
1029+      toReturn.push(arr[i]);
1030+    }
1031+  }
1032+  return toReturn;
1033+}
1034+
1035+/**
1036+ * Convert a value to string.
1037+ * @param value of any type, including array. array cannot be empty.
1038+ * @returns {string} string representation of value
1039+ */
1040+function valueToString(value: any) : string {
1041+  if (typeof value === "number") {
1042+    return value.toString();
1043+  } else if (typeof value === "string") {
1044+    return value;
1045+  } else if (typeof value === "boolean") {
1046+    return value ? "TRUE" : "FALSE";
1047+  } else if (value instanceof Array) {
1048+    return valueToString(value[0]);
1049+  }
1050+}
1051+
1052+
1053+/**
1054+ * Converts any value to a number or throws an error if it cannot coerce it to the number type
1055+ * @param value to convert
1056+ * @returns {number} to return. Will always return a number or throw an error. Never returns undefined.
1057+ */
1058+function valueToNumber(value: any) : number {
1059+  if (typeof value === "number") {
1060+    return value;
1061+  } else if (typeof value === "string") {
1062+    if (value.indexOf(".") > -1) {
1063+      var fl = parseFloat(value);
1064+      if (isNaN(fl)) {
1065+        throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1066+      }
1067+      return fl;
1068+    }
1069+    var fl = parseInt(value);
1070+    if (isNaN(fl)) {
1071+      throw new CellError(ERRORS.VALUE_ERROR, "Function ____ expects number values, but is text and cannot be coerced to a number.");
1072+    }
1073+    return fl;
1074+  } else if (typeof value === "boolean") {
1075+    return value ? 1 : 0;
1076+  }
1077+  return 0;
1078+}
1079+
1080+
1081+export {
1082+  valueToNumber,
1083+  valueToString,
1084+  filterOutStringValues,
1085+  checkArgumentsAtLeastLength,
1086+  checkArgumentsLength
1087+}
1088\ No newline at end of file
1089diff --git a/tests/FormulasTest.ts b/tests/FormulasTest.ts
1090index 4666c62..bb87b00 100644
1091--- a/tests/FormulasTest.ts
1092+++ b/tests/FormulasTest.ts
1093@@ -8,7 +8,7 @@ import { ABS, ACCRINT, ACOS, ACOSH, ACOTH, AND, ARABIC, ASIN, ASINH, ATAN, ATAN2
1094     EFFECT, EOMONTH, ERF, ERFC, EVEN, EXACT, EXPONDIST, FALSE, __COMPLEX, FISHER, FISHERINV, IF,
1095     INT, ISEVEN, ISODD, LN, LOG, LOG10, MAX, MAXA, MEDIAN, MIN, MINA, MOD, NOT, TRUE, ODD, OR,
1096     POWER, ROUND, ROUNDDOWN, ROUNDUP, SIN, SINH, SPLIT, SQRT, SQRTPI, SUM, SUMIF, SUMPRODUCT,
1097-    SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas"
1098+    SUMSQ, SUMX2MY2, SUMX2PY2, TAN, TANH, TRUNC, XOR, YEARFRAC } from "../src/RawFormulas/RawFormulas"
1099 import * as ERRORS from "../src/Errors"
1100 import {assertEquals, assertEqualsDates, assertArrayEquals} from "./utils/Asserts"
1101