RelationalNode.js (7553B)
1 import { getPrecedence } from '../operators.js'; 2 import { escape } from '../../utils/string.js'; 3 import { getSafeProperty } from '../../utils/customs.js'; 4 import { latexOperators } from '../../utils/latex.js'; 5 import { factory } from '../../utils/factory.js'; 6 var name = 'RelationalNode'; 7 var dependencies = ['Node']; 8 export var createRelationalNode = /* #__PURE__ */factory(name, dependencies, _ref => { 9 var { 10 Node 11 } = _ref; 12 13 /** 14 * A node representing a chained conditional expression, such as 'x > y > z' 15 * 16 * @param {String[]} conditionals An array of conditional operators used to compare the parameters 17 * @param {Node[]} params The parameters that will be compared 18 * 19 * @constructor RelationalNode 20 * @extends {Node} 21 */ 22 function RelationalNode(conditionals, params) { 23 if (!(this instanceof RelationalNode)) { 24 throw new SyntaxError('Constructor must be called with the new operator'); 25 } 26 27 if (!Array.isArray(conditionals)) throw new TypeError('Parameter conditionals must be an array'); 28 if (!Array.isArray(params)) throw new TypeError('Parameter params must be an array'); 29 if (conditionals.length !== params.length - 1) throw new TypeError('Parameter params must contain exactly one more element than parameter conditionals'); 30 this.conditionals = conditionals; 31 this.params = params; 32 } 33 34 RelationalNode.prototype = new Node(); 35 RelationalNode.prototype.type = 'RelationalNode'; 36 RelationalNode.prototype.isRelationalNode = true; 37 /** 38 * Compile a node into a JavaScript function. 39 * This basically pre-calculates as much as possible and only leaves open 40 * calculations which depend on a dynamic scope with variables. 41 * @param {Object} math Math.js namespace with functions and constants. 42 * @param {Object} argNames An object with argument names as key and `true` 43 * as value. Used in the SymbolNode to optimize 44 * for arguments from user assigned functions 45 * (see FunctionAssignmentNode) or special symbols 46 * like `end` (see IndexNode). 47 * @return {function} Returns a function which can be called like: 48 * evalNode(scope: Object, args: Object, context: *) 49 */ 50 51 RelationalNode.prototype._compile = function (math, argNames) { 52 var self = this; 53 var compiled = this.params.map(p => p._compile(math, argNames)); 54 return function evalRelationalNode(scope, args, context) { 55 var evalLhs; 56 var evalRhs = compiled[0](scope, args, context); 57 58 for (var i = 0; i < self.conditionals.length; i++) { 59 evalLhs = evalRhs; 60 evalRhs = compiled[i + 1](scope, args, context); 61 var condFn = getSafeProperty(math, self.conditionals[i]); 62 63 if (!condFn(evalLhs, evalRhs)) { 64 return false; 65 } 66 } 67 68 return true; 69 }; 70 }; 71 /** 72 * Execute a callback for each of the child nodes of this node 73 * @param {function(child: Node, path: string, parent: Node)} callback 74 */ 75 76 77 RelationalNode.prototype.forEach = function (callback) { 78 this.params.forEach((n, i) => callback(n, 'params[' + i + ']', this), this); 79 }; 80 /** 81 * Create a new RelationalNode having its childs be the results of calling 82 * the provided callback function for each of the childs of the original node. 83 * @param {function(child: Node, path: string, parent: Node): Node} callback 84 * @returns {RelationalNode} Returns a transformed copy of the node 85 */ 86 87 88 RelationalNode.prototype.map = function (callback) { 89 return new RelationalNode(this.conditionals.slice(), this.params.map((n, i) => this._ifNode(callback(n, 'params[' + i + ']', this)), this)); 90 }; 91 /** 92 * Create a clone of this node, a shallow copy 93 * @return {RelationalNode} 94 */ 95 96 97 RelationalNode.prototype.clone = function () { 98 return new RelationalNode(this.conditionals, this.params); 99 }; 100 /** 101 * Get string representation. 102 * @param {Object} options 103 * @return {string} str 104 */ 105 106 107 RelationalNode.prototype._toString = function (options) { 108 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep'; 109 var precedence = getPrecedence(this, parenthesis); 110 var paramStrings = this.params.map(function (p, index) { 111 var paramPrecedence = getPrecedence(p, parenthesis); 112 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '(' + p.toString(options) + ')' : p.toString(options); 113 }); 114 var operatorMap = { 115 equal: '==', 116 unequal: '!=', 117 smaller: '<', 118 larger: '>', 119 smallerEq: '<=', 120 largerEq: '>=' 121 }; 122 var ret = paramStrings[0]; 123 124 for (var i = 0; i < this.conditionals.length; i++) { 125 ret += ' ' + operatorMap[this.conditionals[i]] + ' ' + paramStrings[i + 1]; 126 } 127 128 return ret; 129 }; 130 /** 131 * Get a JSON representation of the node 132 * @returns {Object} 133 */ 134 135 136 RelationalNode.prototype.toJSON = function () { 137 return { 138 mathjs: 'RelationalNode', 139 conditionals: this.conditionals, 140 params: this.params 141 }; 142 }; 143 /** 144 * Instantiate a RelationalNode from its JSON representation 145 * @param {Object} json An object structured like 146 * `{"mathjs": "RelationalNode", "condition": ..., "trueExpr": ..., "falseExpr": ...}`, 147 * where mathjs is optional 148 * @returns {RelationalNode} 149 */ 150 151 152 RelationalNode.fromJSON = function (json) { 153 return new RelationalNode(json.conditionals, json.params); 154 }; 155 /** 156 * Get HTML representation 157 * @param {Object} options 158 * @return {string} str 159 */ 160 161 162 RelationalNode.prototype.toHTML = function (options) { 163 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep'; 164 var precedence = getPrecedence(this, parenthesis); 165 var paramStrings = this.params.map(function (p, index) { 166 var paramPrecedence = getPrecedence(p, parenthesis); 167 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '<span class="math-parenthesis math-round-parenthesis">(</span>' + p.toHTML(options) + '<span class="math-parenthesis math-round-parenthesis">)</span>' : p.toHTML(options); 168 }); 169 var operatorMap = { 170 equal: '==', 171 unequal: '!=', 172 smaller: '<', 173 larger: '>', 174 smallerEq: '<=', 175 largerEq: '>=' 176 }; 177 var ret = paramStrings[0]; 178 179 for (var i = 0; i < this.conditionals.length; i++) { 180 ret += '<span class="math-operator math-binary-operator math-explicit-binary-operator">' + escape(operatorMap[this.conditionals[i]]) + '</span>' + paramStrings[i + 1]; 181 } 182 183 return ret; 184 }; 185 /** 186 * Get LaTeX representation 187 * @param {Object} options 188 * @return {string} str 189 */ 190 191 192 RelationalNode.prototype._toTex = function (options) { 193 var parenthesis = options && options.parenthesis ? options.parenthesis : 'keep'; 194 var precedence = getPrecedence(this, parenthesis); 195 var paramStrings = this.params.map(function (p, index) { 196 var paramPrecedence = getPrecedence(p, parenthesis); 197 return parenthesis === 'all' || paramPrecedence !== null && paramPrecedence <= precedence ? '\\left(' + p.toTex(options) + '\right)' : p.toTex(options); 198 }); 199 var ret = paramStrings[0]; 200 201 for (var i = 0; i < this.conditionals.length; i++) { 202 ret += latexOperators[this.conditionals[i]] + paramStrings[i + 1]; 203 } 204 205 return ret; 206 }; 207 208 return RelationalNode; 209 }, { 210 isClass: true, 211 isNode: true 212 });