// 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;
/**
* Receive a node that will be replaced by the evaluation of binary operation
* @param {Node} n Replace node
*/
function replaceBinary(n) {
n.type = "Literal";
n.value = eval(`${n.left.raw} ${n.operator} ${n.right.raw}`);
n.raw = String(n.value);
delete n.left;
delete n.right;
}
/**
* Receive a node that will be replaced by the evaluation of the length of an array
* @param {Node} n Replace node
*/
function replaceLength(n) {
n.type = "Literal";
n.value = eval(`${n.object.elements.length}`);
n.raw = String(n.value);
}
/**
* A function that reduce the code using constant folding
* @param {string} code A JS code encapuslated in a String
* @returns {string} Returns code reduced using costant folding
*/
/**
* Receive a node that will be replaced by the evaluation of the length of an array
* @param {Node} n Replace node
*/
function replaceAt(n) {
Object.assign(n, n.object.elements[n.property.value])
delete n.object
delete n.property
}
/**
* Only puts the last item of an array
* @param {Node} n Replace node
* @param {Node} p Parent Node
*/
function replacePop(n, p) {
Object.assign(p, n.object.elements.pop())
delete p.callee
delete p.arguments
}
/**
* Splice elements from elements array
* @param {Node} n Replace node
*/
function replaceSlice(n) {
arrayAux = {
type: "ArrayExpression",
elements: null,
}
arrayAux.elements = n.callee.object.elements.slice(...n.arguments.map(x => x.value))
Object.assign(n, arrayAux)
delete n.callee
delete n.object
delete n.arguments
}
function constantFolding(code) {
const t = espree.parse(code, { ecmaVersion: 6, loc: false });
estraverse.traverse(t, {
leave: function (n, p) {
if (
n.type == "BinaryExpression" &&
n.left.type == "Literal" && n.right.type == "Literal"
) {
replaceBinary(n);
} else if (n.type === "MemberExpression") {
if (n.object.type === "ArrayExpression") {
if (n.property.type === "Identifier" && n.property.name === "length") {
replaceLength(n);
} else if (n.property.type === "Identifier" && n.property.name === "pop") {
replacePop(n, p);
} else if (n.property.type === "Literal") {
replaceAt(n)
}
}
} else if (n.type === "CallExpression") {
if (n.callee.type === "MemberExpression"
&& n.callee.property.type === "Identifier"
&& n.callee.property.name === "slice") {
if (n.arguments.every(x => x.type === "Literal"))
replaceSlice(n)
}
}
},
});
let output = escodegen.generate(t);
/* ... */
return output;
}