Installation
Add ExAST as a dev dependency:
def deps do
[{:ex_ast, "~> 0.11", only: [:dev, :test], runtime: false}]
endFirst search
Find every IO.inspect call in your project:
mix ex_ast.search 'IO.inspect(_)' lib/
Patterns are plain Elixir syntax — _ is a wildcard, variables capture:
# Any arity
mix ex_ast.search 'IO.inspect(...)' lib/
# Capture the argument
mix ex_ast.search 'IO.inspect(expr)' lib/
# Specific two-arg calls
mix ex_ast.search 'IO.inspect(_, _)' lib/
First replace
Remove all dbg calls — the captured expr substitutes into the replacement:
mix ex_ast.replace 'dbg(expr)' 'expr' lib/
Preview without writing files:
mix ex_ast.replace --dry-run 'use Mix.Config' 'import Config' lib/
Programmatic API
Everything the CLI does is available as functions:
# Search files
ExAST.search("lib/", "IO.inspect(_)")
#=> [%{file: "lib/worker.ex", line: 12, source: "IO.inspect(data)", captures: %{}}]
# Replace in files
ExAST.replace("lib/", "dbg(expr)", "expr")
#=> [{"lib/worker.ex", 2}]
# Low-level: work with source strings
ExAST.Patcher.find_all(source_code, "IO.inspect(_)")
#=> [%{node: ..., range: ..., captures: %{}, source: "IO.inspect(data)"}]
ExAST.Patcher.replace_all(source_code, "dbg(expr)", "expr")
#=> "source with dbg calls removed"What's next
- Pattern Language — full syntax reference
- Querying — relationship filters, selectors, capture guards
- Indexing and Code Intelligence — structural terms, selector plans, comments, symbols
- CLI Reference — command-line flags and usage
- Diff — syntax-aware code diffing