Skip to content

Instantly share code, notes, and snippets.

@tschneidereit
Created September 3, 2015 16:01
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 tschneidereit/7e2eee4f6870d00dfb78 to your computer and use it in GitHub Desktop.
Save tschneidereit/7e2eee4f6870d00dfb78 to your computer and use it in GitHub Desktop.
TypeScript module merger
var esprima = require('esprima');
var codegen = require('escodegen');
var fs = require('fs');
function optimizeFile(path) {
console.error("Optimizing file", path);
fs.readFile(path, function (err, data) {
if (err) {
throw err;
}
var ast = esprima.parse(data, { raw: true, tokens: true, range: true, comment: true });
ast = codegen.attachComments(ast, ast.comments, ast.tokens);
console.error("Merged " + optimizeModules(ast.body, 0, 0) + " module bodies.");
fs.writeFile(path, codegen.generate(ast, {comment: true}));
// console.log(codegen.generate(ast, {comment: true}));
});
}
process.argv.slice(2).forEach(function(path) {
optimizeFile(path);
});
function tabs(nesting) {
return ' '.substr(0, nesting * 2);
}
function optimizeModules(nodes, nesting, mergeCount) {
var moduleName = null;
var bodies = [];
console.error(tabs(nesting) + "Optimizing " + nodes.length);
for (var i = 0; i < nodes.length - 1; i++) {
var name = getModuleName(nodes[i]);
var module = getModuleDeclaration(name, nodes[i + 1]);
if (!name || !module) {
if (bodies.length) {
mergeCount = mergeBodies(moduleName, bodies, nodes, nesting, mergeCount);
i -= bodies.length * 2 - 2;
moduleName = null;
bodies = [];
}
continue;
}
if (name !== moduleName) {
if (bodies.length) {
mergeCount = mergeBodies(moduleName, bodies, nodes, nesting, mergeCount);
i -= bodies.length * 2 - 2;
}
moduleName = name;
bodies = [];
console.error(tabs(nesting) + "Module " + moduleName + ' found at ' + i);
}
bodies.push({name: nodes[i], body: module});
i++;
}
if (bodies && bodies.length)
mergeCount = mergeBodies(moduleName, bodies, nodes, nesting, mergeCount);
return mergeCount;
}
function mergeBodies(name, bodies, parentNodeList, nesting, mergeCount) {
mergeCount += bodies.length - 1;
var result = bodies[0].body;
console.error(tabs(nesting) + 'Merging ' + name + ': ' + bodies.length + ' / ' + parentNodeList.length);
for (var i = 1; i < bodies.length; i++) {
var entry = bodies[i];
// console.error(tabs(nesting) + "merging " + name + ' at ' + entry.index, entry.index - context.offset);
result.push.apply(result, entry.body);
parentNodeList.splice(parentNodeList.indexOf(entry.name), 2);
}
return optimizeModules(result, nesting + 1, mergeCount);
}
function getModuleName(node) {
if (node.type !== 'VariableDeclaration' || node.declarations.length !== 1)
return null;
var declaration = node.declarations[0];
if (declaration.type !== 'VariableDeclarator' || declaration.init !== null)
return null;
return declaration.id.name;
}
function getModuleDeclaration(name, node) {
if (node.type !== 'ExpressionStatement')
return null;
var expression = node.expression;
if (expression.type !== 'CallExpression')
return null;
var callee = expression.callee;
if (callee.type !== 'FunctionExpression' || callee.id !== null ||
callee.params.length !== 1 || callee.params[0].name !== name)
{
return null;
}
var args = expression.arguments;
if (args.length !== 1 || args[0].type !== 'LogicalExpression' && args[0].type !== 'AssignmentExpression' ||
args[0].left.name.indexOf(name) === -1)
{
return null;
}
return callee.body.body;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment