I have seen "https://stackoverflow.com/questions/1385335/how-to-generate-function-call-graphs-for-javascript", and tried it. It works well, if you want to get an abstract syntax tree.
Unfortunately Closure Compiler only seems to offer --print_tree
, --print_ast
and --print_pass_graph
. None of them are useful for me.
I want to see a chart of which function calls which other functions.
code2flow does exactly this. Full disclosure, I started this project
To run
$ code2flow source1.js source2.js -o out.gv
Then, open out.gv with graphviz
Edit: For now, this project is unmaintained. I would suggest trying out a different solution before using code2flow.
If you filter the output of closure --print_tree
you get what you want.
For example take the following file:
var fib = function(n) { if (n < 2) { return n; } else { return fib(n - 1) + fib(n - 2); } }; console.log(fib(fib(5)));
Filter the output of closure --print_tree
NAME fib 1 FUNCTION 1 CALL 5 NAME fib 5 SUB 5 NAME a 5 NUMBER 1.0 5 CALL 5 NAME fib 5 SUB 5 NAME a 5 NUMBER 2.0 5 EXPR_RESULT 9 CALL 9 GETPROP 9 NAME console 9 STRING log 9 CALL 9 CALL 9 NAME fib 9 CALL 9 CALL 9 NAME fib 9 NUMBER 5.0 9
And you can see all the call statements.
I wrote the following scripts to do this.
./call_tree
#! /usr/bin/env sh function make_tree() { closure --print_tree $1 | grep $1 } function parse_tree() { gawk -f parse_tree.awk } if [[ "$1" = "--tree" ]]; then make_tree $2 else make_tree $1 | parse_tree fi
parse_tree.awk
BEGIN { lines_c = 0 indent_width = 4 indent_offset = 0 string_offset = "" calling = 0 call_indent = 0 } { sub(/\[source_file.*$/, "") sub(/\[free_call.*$/, "") } /SCRIPT/ { indent_offset = calculate_indent($0) root_indent = indent_offset - 1 } /FUNCTION/ { pl = get_previous_line() if (calculate_indent(pl) < calculate_indent($0)) print pl print } { lines_v[lines_c] = $0 lines_c += 1 } { indent = calculate_indent($0) if (indent <= call_indent) { calling = 0 } if (calling) { print } } /CALL/ { calling = 1 call_indent = calculate_indent($0) print } /EXPR/{ line_indent = calculate_indent($0) if (line_indent == root_indent) { if ($0 !~ /(FUNCTION)/) { print } } } function calculate_indent(line) { match(line, /^ */) return int(RLENGTH / indent_width) - indent_offset } function get_previous_line() { return lines_v[lines_c - 1] }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With