Skip to content

Instantly share code, notes, and snippets.

@keis
Created November 26, 2013 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save keis/7658516 to your computer and use it in GitHub Desktop.
Save keis/7658516 to your computer and use it in GitHub Desktop.
var fs = require('fs'),
esprima = require('esprima'),
escodegen = require('escodegen'),
uglify = require('uglifyjs'),
_ = require('underscore');
function findScope(tree, key) {
var q = [],
scope,
node;
function push(node) {
node.scope = scope;
q.push(node);
}
push(tree);
while (node = q.pop()) {
if (key(node)) {
return node.scope;
}
if (node.type == 'BlockStatement') {
scope = node;
}
if (node.expression) {
push(node.expression);
}
if (node.body) {
node.body.forEach ? node.body.forEach(push) : push(node.body);
}
if (node.callee) {
node.arguments.forEach(push);
push(node.callee);
}
if (node.object) {
push(node.object);
}
}
}
function assignment(node) {
var i,
d;
if (node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression') {
return node.expression;
}
if (node.type === 'VariableDeclaration') {
for (i = 0; i < node.declarations.length; i++) {
d = node.declarations[i];
if (d.init && d.init.type === 'AssignmentExpression') {
return d.init;
}
}
}
return null;
}
function exportedFunctions(node) {
var funs = [],
right,
exp;
if (exp = assignment(node)) {
funs.push(exp.left);
right = exp.right;
while (right && right.type == 'AssignmentExpression') {
funs.push(right.left);
right = right.right;
}
if (~['FunctionExpression', 'CallExpression'].indexOf(right.type)) {
return funs;
}
}
return false;
}
function squiggle(file, wanted) {
fs.readFile(file, function (err, data) {
var tree,
main,
newBody,
out;
if (err) {
return console.error(err);
}
tree = esprima.parse(data);
main = findScope(tree, function (node) {
var i;
if (node.type === 'VariableDeclaration') {
for (i = 0; i < node.declarations.length; i++) {
d = node.declarations[i];
if (d.id.name == '_') {
return true;
}
}
}
return false;
});
newBody = [];
main.body.forEach(function (node) {
var funs,
ok;
if (funs = exportedFunctions(node)) {
funs.forEach(function (f) {
if (~wanted.indexOf(f.property.name)) {
ok = true;
}
});
if (!ok) {
return;
}
}
newBody.push(node);
});
main.body = newBody;
// TODO: Avoid parsing again. uglify2 supports converting from esprima AST
out = uglify.minify(escodegen.generate(tree), {
fromString: true,
compress: true,
mangle: false,
warnings: true,
output: { beautify: true }
});
console.log(out['code']);
});
}
squiggle(process.argv[2], process.argv.slice(3));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment