AccessorNode.js (6815B)
1 "use strict"; 2 3 Object.defineProperty(exports, "__esModule", { 4 value: true 5 }); 6 exports.createAccessorNode = void 0; 7 8 var _is = require("../../utils/is.js"); 9 10 var _customs = require("../../utils/customs.js"); 11 12 var _factory = require("../../utils/factory.js"); 13 14 var _access = require("./utils/access.js"); 15 16 var name = 'AccessorNode'; 17 var dependencies = ['subset', 'Node']; 18 var createAccessorNode = /* #__PURE__ */(0, _factory.factory)(name, dependencies, function (_ref) { 19 var subset = _ref.subset, 20 Node = _ref.Node; 21 var access = (0, _access.accessFactory)({ 22 subset: subset 23 }); 24 /** 25 * @constructor AccessorNode 26 * @extends {Node} 27 * Access an object property or get a matrix subset 28 * 29 * @param {Node} object The object from which to retrieve 30 * a property or subset. 31 * @param {IndexNode} index IndexNode containing ranges 32 */ 33 34 function AccessorNode(object, index) { 35 if (!(this instanceof AccessorNode)) { 36 throw new SyntaxError('Constructor must be called with the new operator'); 37 } 38 39 if (!(0, _is.isNode)(object)) { 40 throw new TypeError('Node expected for parameter "object"'); 41 } 42 43 if (!(0, _is.isIndexNode)(index)) { 44 throw new TypeError('IndexNode expected for parameter "index"'); 45 } 46 47 this.object = object || null; 48 this.index = index; // readonly property name 49 50 Object.defineProperty(this, 'name', { 51 get: function () { 52 if (this.index) { 53 return this.index.isObjectProperty() ? this.index.getObjectProperty() : ''; 54 } else { 55 return this.object.name || ''; 56 } 57 }.bind(this), 58 set: function set() { 59 throw new Error('Cannot assign a new name, name is read-only'); 60 } 61 }); 62 } 63 64 AccessorNode.prototype = new Node(); 65 AccessorNode.prototype.type = 'AccessorNode'; 66 AccessorNode.prototype.isAccessorNode = true; 67 /** 68 * Compile a node into a JavaScript function. 69 * This basically pre-calculates as much as possible and only leaves open 70 * calculations which depend on a dynamic scope with variables. 71 * @param {Object} math Math.js namespace with functions and constants. 72 * @param {Object} argNames An object with argument names as key and `true` 73 * as value. Used in the SymbolNode to optimize 74 * for arguments from user assigned functions 75 * (see FunctionAssignmentNode) or special symbols 76 * like `end` (see IndexNode). 77 * @return {function} Returns a function which can be called like: 78 * evalNode(scope: Object, args: Object, context: *) 79 */ 80 81 AccessorNode.prototype._compile = function (math, argNames) { 82 var evalObject = this.object._compile(math, argNames); 83 84 var evalIndex = this.index._compile(math, argNames); 85 86 if (this.index.isObjectProperty()) { 87 var prop = this.index.getObjectProperty(); 88 return function evalAccessorNode(scope, args, context) { 89 // get a property from an object evaluated using the scope. 90 return (0, _customs.getSafeProperty)(evalObject(scope, args, context), prop); 91 }; 92 } else { 93 return function evalAccessorNode(scope, args, context) { 94 var object = evalObject(scope, args, context); 95 var index = evalIndex(scope, args, object); // we pass object here instead of context 96 97 return access(object, index); 98 }; 99 } 100 }; 101 /** 102 * Execute a callback for each of the child nodes of this node 103 * @param {function(child: Node, path: string, parent: Node)} callback 104 */ 105 106 107 AccessorNode.prototype.forEach = function (callback) { 108 callback(this.object, 'object', this); 109 callback(this.index, 'index', this); 110 }; 111 /** 112 * Create a new AccessorNode having it's childs be the results of calling 113 * the provided callback function for each of the childs of the original node. 114 * @param {function(child: Node, path: string, parent: Node): Node} callback 115 * @returns {AccessorNode} Returns a transformed copy of the node 116 */ 117 118 119 AccessorNode.prototype.map = function (callback) { 120 return new AccessorNode(this._ifNode(callback(this.object, 'object', this)), this._ifNode(callback(this.index, 'index', this))); 121 }; 122 /** 123 * Create a clone of this node, a shallow copy 124 * @return {AccessorNode} 125 */ 126 127 128 AccessorNode.prototype.clone = function () { 129 return new AccessorNode(this.object, this.index); 130 }; 131 /** 132 * Get string representation 133 * @param {Object} options 134 * @return {string} 135 */ 136 137 138 AccessorNode.prototype._toString = function (options) { 139 var object = this.object.toString(options); 140 141 if (needParenthesis(this.object)) { 142 object = '(' + object + ')'; 143 } 144 145 return object + this.index.toString(options); 146 }; 147 /** 148 * Get HTML representation 149 * @param {Object} options 150 * @return {string} 151 */ 152 153 154 AccessorNode.prototype.toHTML = function (options) { 155 var object = this.object.toHTML(options); 156 157 if (needParenthesis(this.object)) { 158 object = '<span class="math-parenthesis math-round-parenthesis">(</span>' + object + '<span class="math-parenthesis math-round-parenthesis">)</span>'; 159 } 160 161 return object + this.index.toHTML(options); 162 }; 163 /** 164 * Get LaTeX representation 165 * @param {Object} options 166 * @return {string} 167 */ 168 169 170 AccessorNode.prototype._toTex = function (options) { 171 var object = this.object.toTex(options); 172 173 if (needParenthesis(this.object)) { 174 object = '\\left(\' + object + \'\\right)'; 175 } 176 177 return object + this.index.toTex(options); 178 }; 179 /** 180 * Get a JSON representation of the node 181 * @returns {Object} 182 */ 183 184 185 AccessorNode.prototype.toJSON = function () { 186 return { 187 mathjs: 'AccessorNode', 188 object: this.object, 189 index: this.index 190 }; 191 }; 192 /** 193 * Instantiate an AccessorNode from its JSON representation 194 * @param {Object} json An object structured like 195 * `{"mathjs": "AccessorNode", object: ..., index: ...}`, 196 * where mathjs is optional 197 * @returns {AccessorNode} 198 */ 199 200 201 AccessorNode.fromJSON = function (json) { 202 return new AccessorNode(json.object, json.index); 203 }; 204 /** 205 * Are parenthesis needed? 206 * @private 207 */ 208 209 210 function needParenthesis(node) { 211 // TODO: maybe make a method on the nodes which tells whether they need parenthesis? 212 return !((0, _is.isAccessorNode)(node) || (0, _is.isArrayNode)(node) || (0, _is.isConstantNode)(node) || (0, _is.isFunctionNode)(node) || (0, _is.isObjectNode)(node) || (0, _is.isParenthesisNode)(node) || (0, _is.isSymbolNode)(node)); 213 } 214 215 return AccessorNode; 216 }, { 217 isClass: true, 218 isNode: true 219 }); 220 exports.createAccessorNode = createAccessorNode;