sono finalmente riuscito questo utilizzando UglifyJS2 e Dot/GraphViz, in una sorta di combinazione tra la risposta di cui sopra e le risposte alla domanda collegata.
La parte mancante, per me, era come filtrare l'AST analizzato. Si scopre che UglifyJS ha l'oggetto TreeWalker, che sostanzialmente applica una funzione a ciascun nodo dell'AST. Questo è il codice che ho finora:
//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, '}');
l'eseguo con node, e poi mettere l'uscita attraverso
dot -Tpng -o graph_name.png dot_file_name.dot
Note:
Si dà un grafico piuttosto semplice - solo in bianco e nero e senza formattazione.
Non cattura affatto ajax e presumibilmente non corrisponde a eval
o with
, come others have mentioned.
Inoltre, come al solito include nel grafico: funzioni chiamate da altre funzioni (e di conseguenza funzioni che chiamano altre funzioni), funzioni chiamate indipendenti, funzioni AND definite ma non chiamate.
Come risultato di tutto ciò, possono mancare le cose che sono rilevanti o includere cose che non lo sono.È comunque un inizio e sembra realizzare ciò che cercavo, e ciò che mi ha portato a questa domanda in primo luogo.
+1 ottima domanda - – miku
Perché non usi gli strumenti di sviluppo integrati nel supporto per la creazione di profili di javascript? – Tushar
Sembra che il thread originale sia andato e il link sia ora rotto. :-( –