Quickstart
codeanalyzer-typescript points at a TypeScript or JavaScript project and produces one typed artifact — its symbol table, call graph, and external symbols. Three steps below: build it, run it against a project, and read the result.
-
Build the CLI.
Terminal window git clone https://github.com/codellm-devkit/codeanalyzer-tscd codeanalyzer-tsbun installbun run build # -> dist/codeanalyzer-typescript (standalone native binary)That compiles a standalone binary at
dist/codeanalyzer-typescript— no Bun or Node needed to run it afterward. To skip the compile step, run from source instead withbun run start -- …. -
Run it against a project.
Point
--inputat any TypeScript/JavaScript project root and--outputat a directory for the result.Terminal window ./dist/codeanalyzer-typescript --input ./my-ts-project --output ./outBy default the analyzer first materializes the project’s
node_modules(so imported library calls resolve), walks every source file, builds the symbol table and call graph, and writes./out/analysis.json. Intermediate state is cached under.codeanalyzer/in the project. -
Read the result.
analysis.jsonis a singleTSApplicationobject with four top-level keys.Terminal window jq 'keys' ./out/analysis.json# [ "call_graph", "entrypoints", "external_symbols", "symbol_table" ]jq '.symbol_table | length' ./out/analysis.json # modules analyzedjq '.call_graph | length' ./out/analysis.json # call edgesjq '.external_symbols | length' ./out/analysis.json # phantom library targetsThat’s it — a directory of source files is now a typed, queryable model of the program.
Load it into a graph
Section titled “Load it into a graph”The call graph is a flat list of source -> target edges keyed by callable signature, so it drops straight into any graph library — here, Python’s networkx:
import jsonimport networkx as nx
app = json.load(open("./out/analysis.json"))
g = nx.DiGraph()for edge in app["call_graph"]: g.add_edge(edge["source"], edge["target"])
print(g.number_of_nodes(), "nodes,", g.number_of_edges(), "edges")# Is a sink reachable from some caller? A graph query, not a guess.# print(nx.has_path(g, caller_sig, sink_sig))Edge endpoints are either a real TSCallable.signature from the symbol table or a TSExternalSymbol.signature for a call into a library — both are plain strings, so external boundaries show up as nodes in the graph rather than disappearing.
Go deeper with level 2
Section titled “Go deeper with level 2”The default run is level 1: the TypeScript checker resolves the call graph, RTA expands virtual dispatch, and phantom nodes capture external calls — fast, no extra tooling. Level 2 adds CodeQL enrichment for the dynamic cases the checker can’t reach.
./dist/codeanalyzer-typescript --input ./my-ts-project --output ./out --analysis-level 2