私はついにUglifyJS2とDot/GraphVizを使用して、上記の回答とリンクされた質問への回答を組み合わせてこれを管理しました。
私にとって欠けていたのは、解析されたASTをフィルタリングする方法でした。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, '}');
私はそれをノードで実行し、次に出力を通過させます
dot -Tpng -o graph_name.png dot_file_name.dot
ノート:
それはかなり基本的なグラフを提供します-白黒のみでフォーマットはありません。
他の人が言及しているように、それはajaxをまったくキャッチせず、おそらくそのようなものでもeval
、with
どちらでもないでしょう。
また、現状では、他の関数によって呼び出される関数(したがって、他の関数を呼び出す関数)、独立して呼び出される関数、および定義されているが呼び出されていない関数がグラフに含まれています。
これらすべての結果として、関連性のあるものを見逃したり、関連性のないものを含めたりする可能性があります。しかし、それは始まりであり、私が求めていたもの、そしてそもそもこの質問に私を導いたものを達成しているように見えます。