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