name:
src/Formulas/Logical.ts
-rw-r--r--
4585
1import {
2 ArgsChecker
3} from "../Utilities/ArgsChecker";
4import {
5 TypeConverter
6} from "../Utilities/TypeConverter";
7import {
8 ValueError,
9 RefError
10} from "../Errors";
11
12/**
13 * Returns true if all of the provided arguments are logically true, and false if any of the provided arguments are
14 * logically false.
15 * @param values At least one expression or reference to a cell containing an expression that represents some logical
16 * value, i.e. TRUE or FALSE, or an expression that can be coerced to a logical value.
17 * @returns {boolean} if all values are logically true.
18 * @constructor
19 */
20let AND = function (...values) {
21 ArgsChecker.checkAtLeastLength(values, 1, "AND");
22 let result = true;
23 for (let i = 0; i < values.length; i++) {
24 if (typeof values[i] === "string") {
25 throw new ValueError("AND expects boolean values. But '" + values[i]
26 + "' is a text and cannot be coerced to a boolean.")
27 } else if (values[i] instanceof Array) {
28 if (!AND.apply(this, values[i])) {
29 result = false;
30 break;
31 }
32 } else if (!values[i]) {
33 result = false;
34 break;
35 }
36 }
37 return result;
38};
39
40/**
41 * Tests whether two strings are identical, returning true if they are.
42 * @param one - The first string to compare
43 * @param two - The second string to compare
44 * @returns {boolean}
45 * @constructor
46 */
47let EXACT = function (one, two) {
48 ArgsChecker.checkLength(arguments, 2, "EXACT");
49 one = TypeConverter.firstValue(one);
50 two = TypeConverter.firstValue(two);
51 return one.toString() === two.toString();
52};
53
54/**
55 * Returns true.
56 * @returns {boolean} true boolean
57 * @constructor
58 */
59let TRUE = function () : boolean {
60 ArgsChecker.checkLength(arguments, 0, "TRUE");
61 return true;
62};
63
64/**
65 * Returns false.
66 * @returns {boolean} false boolean
67 * @constructor
68 */
69let FALSE = function () : boolean {
70 ArgsChecker.checkLength(arguments, 0, "FALSE");
71 return false;
72};
73
74/**
75 * Returns the opposite of a logical value - NOT(TRUE) returns FALSE; NOT(FALSE) returns TRUE.
76 * @param value - An expression or reference to a cell holding an expression that represents some logical value.
77 * @returns {boolean} opposite of a logical value input
78 * @constructor
79 */
80let NOT = function (value) : boolean {
81 ArgsChecker.checkLength(arguments, 1, "NOT");
82 if (typeof(value) === "boolean") {
83 return !value;
84 }
85 if (typeof(value) === "string") {
86 if (value === "") {
87 return true;
88 }
89 throw new ValueError("Function NOT parameter 1 expects boolean values. But '" + value
90 + "' is a text and cannot be coerced to a boolean.")
91 }
92 if (typeof(value) === "number") {
93 return value === 0;
94 }
95 if (value instanceof Array) {
96 if (value.length === 0) {
97 throw new RefError("Reference does not exist.");
98 }
99 return NOT(value[0]);
100 }
101};
102
103/**
104 * Returns true if any of the provided arguments are logically true, and false if all of the provided arguments are
105 * logically false.
106 * @param values An expression or reference to a cell containing an expression that represents some logical value, i.e.
107 * TRUE or FALSE, or an expression that can be coerced to a logical value.
108 * @returns {boolean}
109 * @constructor
110 */
111let OR = function (...values) {
112 ArgsChecker.checkAtLeastLength(values, 1, "OR");
113 for (let i = 0; i < values.length; i++) {
114 if (values[i] instanceof Array) {
115 if (values[i].length === 0) {
116 throw new RefError("Reference does not exist.");
117 }
118 if (OR.apply(this, values[i])) {
119 return true;
120 }
121 } else if (TypeConverter.valueToBoolean(values[i])) {
122 return true;
123 }
124 }
125 return false;
126};
127
128/**
129 * Exclusive or or exclusive disjunction is a logical operation that outputs true only when inputs differ.
130 * @param values to check for exclusivity.
131 * @returns {boolean} returns true if only one input is considered logically true.
132 * @constructor
133 */
134let XOR = function (...values) {
135 ArgsChecker.checkAtLeastLength(values, 1, "XOR");
136 let alreadyTruthy = false;
137 for (let i = 0; i < values.length; i++) {
138 if (values[i] instanceof Array) {
139 if (values[i].length === 0) {
140 throw new RefError("Reference does not exist.");
141 }
142 if (XOR.apply(this, values[i])) {
143 if (alreadyTruthy) {
144 return false;
145 }
146 alreadyTruthy = true;
147 }
148 } else if (TypeConverter.valueToBoolean(values[i])) {
149 if (alreadyTruthy) {
150 return false;
151 }
152 alreadyTruthy = true;
153 }
154 }
155 return alreadyTruthy;
156};
157
158export {
159 AND,
160 EXACT,
161 TRUE,
162 FALSE,
163 NOT,
164 OR,
165 XOR
166}