spreadsheet
typeScript/javascript spreadsheet parser, with formulas.
git clone https://git.vogt.world/spreadsheet.git
Log | Files | README.md
← All files
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}