я, наконец, удалось это с помощью UglifyJS2 и Dot/GraphViz, в какой-то комбинации вышеуказанного ответа и ответов на связанный вопрос.
Недостающая часть для меня - это то, как фильтровать анализируемый АСТ. Оказывается, что UglifyJS имеет объект TreeWalker, который в основном применяет функцию к каждому узлу AST. Это код, который я до сих пор:
//to be run using nodejs
var UglifyJS = require('uglify-js')
var fs = require('fs');
var util = require('util');
var file = 'path/to/file...';
//read in the code
var code = fs.readFileSync(file, "utf8");
//parse it to AST
var toplevel = UglifyJS.parse(code);
//open the output DOT file
var out = fs.openSync('path/to/output/file...', 'w');
//output the start of a directed graph in DOT notation
fs.writeSync(out, 'digraph test{\n');
//use a tree walker to examine each node
var walker = new UglifyJS.TreeWalker(function(node){
//check for function calls
if (node instanceof UglifyJS.AST_Call) {
if(node.expression.name !== undefined)
{
//find where the calling function is defined
var p = walker.find_parent(UglifyJS.AST_Defun);
if(p !== undefined)
{
//filter out unneccessary stuff, eg calls to external libraries or constructors
if(node.expression.name == "$" || node.expression.name == "Number" || node.expression.name =="Date")
{
//NOTE: $ is from jquery, and causes problems if it's in the DOT file.
//It's also very frequent, so even replacing it with a safe string
//results in a very cluttered graph
}
else
{
fs.writeSync(out, p.name.name);
fs.writeSync(out, " -> ");
fs.writeSync(out, node.expression.name);
fs.writeSync(out, "\n");
}
}
else
{
//it's a top level function
fs.writeSync(out, node.expression.name);
fs.writeSync(out, "\n");
}
}
}
if(node instanceof UglifyJS.AST_Defun)
{
//defined but not called
fs.writeSync(out, node.name.name);
fs.writeSync(out, "\n");
}
});
//analyse the AST
toplevel.walk(walker);
//finally, write out the closing bracket
fs.writeSync(out, '}');
я запускаю его с node, а затем положить выход через
dot -Tpng -o graph_name.png dot_file_name.dot
Примечания:
Это дает довольно основной график - только черно-белый и без форматирования.
Это не ловушка ajax вообще, и, предположительно, не такие вещи, как eval
или with
, либо others have mentioned.
Кроме того, поскольку он стоит, он включает в себя: функции, называемые другими функциями (и, следовательно, функциями, которые вызывают другие функции), функции, которые называются независимыми, и функции, которые определены, но не вызваны.
В результате все это может пропустить то, что имеет отношение к делу, или включать в себя то, что нет.Это, однако, начало, и, похоже, я выполнил то, что было после, и что привело меня к этому вопросу в первую очередь.
+1 отличный вопрос - – miku
Почему вы не используете инструменты dev, встроенные в поддержку профилирования javascript? – Tushar
Похоже, что исходная нить прошла, и теперь ссылка сломана. :-( –