Source: constant-folding.js

// 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 {*} Return single element from passed Node
 */
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) {
      if (node.type == 'ExpressionStatement' && node.expression.type == 'CallExpression' && node.expression.callee.object.type == 'ArrayExpression') {
        transNode(node, node.expression.arguments);
      }
      if (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);
}