All files constant-folding.js

53.65% Statements 22/41
52.38% Branches 11/21
38.46% Functions 5/13
59.45% Lines 22/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88  1x 1x 1x 1x 1x   1x   1x                 1x       1x   1x                                                               1x 1x 1x 1x 1x                     1x 1x   7x     7x     7x 1x         1x  
// See https://github.com/babel/minify/tree/master/packages/babel-plugin-minify-constant-folding
const fs = require("fs");
const deb = require('../src/deb.js');
const escodegen = require("escodegen");
const espree = require("espree");
const estraverse = require("estraverse");
 
"use strict";
 
module.exports = constantFolding;
 
/**
 * This function gets passed by a Node and depending on its type will perform 
 * different operations.
 * @param {Obect} elem Single subNode
 * @returns 
 */
function getValues(elem) {
    let types = {
      'Literal' : () => {return elem.raw},
      'Identifier' : () => {return elem.name},
      'ArrayExpression' : () => {return `${elem.elements.map(l => getValues(l))}`},
      'BinaryExpression' : () => {return `${eval(`${elem.left.raw} ${elem.operator} ${elem.right.raw}`)}`}
    }
    return types[elem.type]();
}
 
/**
 * This function gets passed two arguments and perform a transformation in the node
 * depending different parameters. Then it creates a new node object that will substitute
 * the passed one.
 * @param {Object} n Node object in which constant folding will be applied
 * @param {*} args Possible arguments this node has ex: [a].concat([b]), [b] are the args here
 */
function transNode(n, args) {
  let argString = ""
  let auxstring = "";
  let a = n.expression;
 
  if (args) {
    a = n.expression.callee;
    argString += `(${(args) ? args.map(arg => getValues(arg)) : ''})`;
  }
  if (a.property.type == 'Literal')
    auxString = `[${a.object.elements.map(el => getValues(el))}][${getValues(a.property)}]` + argString;
  else 
    auxString = `[${a.object.elements.map(el => getValues(el))}].${getValues(a.property)}` + argString;
 
  n.expression = espree.parse(eval(auxString)).body[0].expression;
}
 
/**
 * This Function takes a Node of type BinaryExpression and perform constant Folding on it
 * @param {Object} n Node with a type of BinaryExpression
 */
function transLiteralNode(n) {
  n.value = Number(getValues(n));
  n.raw = String(n.value);
  n.type = 'Literal';
  delete n.left;
  delete n.rigth;
}
 
/**
 * This function get passed some code and then it forms an AST tree with it.
 * After it traverses the tree doing constant folding in different nodes in 
 * which it is possible to perform it 
 * @param {string} code The javascript input code
 * @returns {string} Generated js code from the resultant tree
 */
function constantFolding(code) {
  let ast = espree.parse(code, {ecmaVersion: espree.latestEcmaVersion});
  estraverse.traverse(ast, {
    leave: function(node, parent) {
      Iif (node.type == 'ExpressionStatement' && node.expression.type == 'CallExpression' && node.expression.callee.object.type == 'ArrayExpression') {
        transNode(node, node.expression.arguments);
      }
      Iif (node.type == 'ExpressionStatement' && node.expression.type == 'MemberExpression' && node.expression.object.type == 'ArrayExpression') {
        transNode(node);
      }
      if(node.type == 'BinaryExpression' && node.left.type == 'Literal' && node.right.type == 'Literal') {
        transLiteralNode(node);
      }
    }
  });
  //deb(ast);
  return escodegen.generate(ast);
}