simple-squiggle

A restricted subset of Squiggle
Log | Files | Refs | README

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 });