ObjectNode.js (6660B)
1 import { isNode } from '../../utils/is.js'; 2 import { escape, stringify } from '../../utils/string.js'; 3 import { isSafeProperty } from '../../utils/customs.js'; 4 import { hasOwnProperty } from '../../utils/object.js'; 5 import { factory } from '../../utils/factory.js'; 6 var name = 'ObjectNode'; 7 var dependencies = ['Node']; 8 export var createObjectNode = /* #__PURE__ */factory(name, dependencies, _ref => { 9 var { 10 Node 11 } = _ref; 12 13 /** 14 * @constructor ObjectNode 15 * @extends {Node} 16 * Holds an object with keys/values 17 * @param {Object.<string, Node>} [properties] object with key/value pairs 18 */ 19 function ObjectNode(properties) { 20 if (!(this instanceof ObjectNode)) { 21 throw new SyntaxError('Constructor must be called with the new operator'); 22 } 23 24 this.properties = properties || {}; // validate input 25 26 if (properties) { 27 if (!(typeof properties === 'object') || !Object.keys(properties).every(function (key) { 28 return isNode(properties[key]); 29 })) { 30 throw new TypeError('Object containing Nodes expected'); 31 } 32 } 33 } 34 35 ObjectNode.prototype = new Node(); 36 ObjectNode.prototype.type = 'ObjectNode'; 37 ObjectNode.prototype.isObjectNode = true; 38 /** 39 * Compile a node into a JavaScript function. 40 * This basically pre-calculates as much as possible and only leaves open 41 * calculations which depend on a dynamic scope with variables. 42 * @param {Object} math Math.js namespace with functions and constants. 43 * @param {Object} argNames An object with argument names as key and `true` 44 * as value. Used in the SymbolNode to optimize 45 * for arguments from user assigned functions 46 * (see FunctionAssignmentNode) or special symbols 47 * like `end` (see IndexNode). 48 * @return {function} Returns a function which can be called like: 49 * evalNode(scope: Object, args: Object, context: *) 50 */ 51 52 ObjectNode.prototype._compile = function (math, argNames) { 53 var evalEntries = {}; 54 55 for (var key in this.properties) { 56 if (hasOwnProperty(this.properties, key)) { 57 // we stringify/parse the key here to resolve unicode characters, 58 // so you cannot create a key like {"co\\u006Estructor": null} 59 var stringifiedKey = stringify(key); 60 var parsedKey = JSON.parse(stringifiedKey); 61 62 if (!isSafeProperty(this.properties, parsedKey)) { 63 throw new Error('No access to property "' + parsedKey + '"'); 64 } 65 66 evalEntries[parsedKey] = this.properties[key]._compile(math, argNames); 67 } 68 } 69 70 return function evalObjectNode(scope, args, context) { 71 var obj = {}; 72 73 for (var _key in evalEntries) { 74 if (hasOwnProperty(evalEntries, _key)) { 75 obj[_key] = evalEntries[_key](scope, args, context); 76 } 77 } 78 79 return obj; 80 }; 81 }; 82 /** 83 * Execute a callback for each of the child nodes of this node 84 * @param {function(child: Node, path: string, parent: Node)} callback 85 */ 86 87 88 ObjectNode.prototype.forEach = function (callback) { 89 for (var key in this.properties) { 90 if (hasOwnProperty(this.properties, key)) { 91 callback(this.properties[key], 'properties[' + stringify(key) + ']', this); 92 } 93 } 94 }; 95 /** 96 * Create a new ObjectNode having it's childs be the results of calling 97 * the provided callback function for each of the childs of the original node. 98 * @param {function(child: Node, path: string, parent: Node): Node} callback 99 * @returns {ObjectNode} Returns a transformed copy of the node 100 */ 101 102 103 ObjectNode.prototype.map = function (callback) { 104 var properties = {}; 105 106 for (var key in this.properties) { 107 if (hasOwnProperty(this.properties, key)) { 108 properties[key] = this._ifNode(callback(this.properties[key], 'properties[' + stringify(key) + ']', this)); 109 } 110 } 111 112 return new ObjectNode(properties); 113 }; 114 /** 115 * Create a clone of this node, a shallow copy 116 * @return {ObjectNode} 117 */ 118 119 120 ObjectNode.prototype.clone = function () { 121 var properties = {}; 122 123 for (var key in this.properties) { 124 if (hasOwnProperty(this.properties, key)) { 125 properties[key] = this.properties[key]; 126 } 127 } 128 129 return new ObjectNode(properties); 130 }; 131 /** 132 * Get string representation 133 * @param {Object} options 134 * @return {string} str 135 * @override 136 */ 137 138 139 ObjectNode.prototype._toString = function (options) { 140 var entries = []; 141 142 for (var key in this.properties) { 143 if (hasOwnProperty(this.properties, key)) { 144 entries.push(stringify(key) + ': ' + this.properties[key].toString(options)); 145 } 146 } 147 148 return '{' + entries.join(', ') + '}'; 149 }; 150 /** 151 * Get a JSON representation of the node 152 * @returns {Object} 153 */ 154 155 156 ObjectNode.prototype.toJSON = function () { 157 return { 158 mathjs: 'ObjectNode', 159 properties: this.properties 160 }; 161 }; 162 /** 163 * Instantiate an OperatorNode from its JSON representation 164 * @param {Object} json An object structured like 165 * `{"mathjs": "ObjectNode", "properties": {...}}`, 166 * where mathjs is optional 167 * @returns {ObjectNode} 168 */ 169 170 171 ObjectNode.fromJSON = function (json) { 172 return new ObjectNode(json.properties); 173 }; 174 /** 175 * Get HTML representation 176 * @param {Object} options 177 * @return {string} str 178 * @override 179 */ 180 181 182 ObjectNode.prototype.toHTML = function (options) { 183 var entries = []; 184 185 for (var key in this.properties) { 186 if (hasOwnProperty(this.properties, key)) { 187 entries.push('<span class="math-symbol math-property">' + escape(key) + '</span>' + '<span class="math-operator math-assignment-operator math-property-assignment-operator math-binary-operator">:</span>' + this.properties[key].toHTML(options)); 188 } 189 } 190 191 return '<span class="math-parenthesis math-curly-parenthesis">{</span>' + entries.join('<span class="math-separator">,</span>') + '<span class="math-parenthesis math-curly-parenthesis">}</span>'; 192 }; 193 /** 194 * Get LaTeX representation 195 * @param {Object} options 196 * @return {string} str 197 */ 198 199 200 ObjectNode.prototype._toTex = function (options) { 201 var entries = []; 202 203 for (var key in this.properties) { 204 if (hasOwnProperty(this.properties, key)) { 205 entries.push('\\mathbf{' + key + ':} & ' + this.properties[key].toTex(options) + '\\\\'); 206 } 207 } 208 209 return "\\left\\{\\begin{array}{ll}".concat(entries.join('\n'), "\\end{array}\\right\\}"); 210 }; 211 212 return ObjectNode; 213 }, { 214 isClass: true, 215 isNode: true 216 });