Find leftover console.log calls by AST, not text grep
ast-grep matches syntax trees, not strings — it won't false-positive on a `// console.log(...)` comment or a string that happens to contain the text "console.log(". Point it at any code shape (a banned call, a deprecated API, a debugger statement) and rank hits by file for a pre-deploy cleanup pass.
Setup
- → npm install -g @ast-grep/cli
Cost per run
free
The one-liner
$ ast-grep run -p 'console.log($$$)' -l ts --json=compact . | jq -r '.[].file' | sort | uniq -c | sort -rnWhat each stage does
- [01] ast-grep
ast-grep run -p 'console.log($$$)' -l ts --json=compact .Structural search: match any call to console.log with any arguments ($$$ is a multi-node wildcard) across every .ts file under the current directory. --json=compact emits one JSON object per match with file/line/matched text. - [02] jq
jq -r '.[].file'Pull just the file path out of every match object. - [03] sort/uniq
sort | uniq -c | sort -rnCount matches per file and rank the worst offenders first — a punch list for cleanup, not just a wall of hits.
Expected output (sample)
36 scripts/forecast-lab.ts 31 scripts/link-audit.ts 27 server/services/scheduler.ts 13 server/services/timelineSourceScraper.ts 9 server/services/timelineCollector.ts 9 scripts/add-timeline-urls.ts 9 scripts/add-timeline-urls-serper.ts 8 scripts/run-batch-job.ts 8 scripts/check-timeline.ts 6 server/services/timeGptForecaster.ts ... (37 files total)
Caveats & tips
- Verified on @ast-grep/cli 0.45.3 (npm), run for real against this monorepo's trends101/ TypeScript app (37 files, 200+ matches) — swap the pattern and target directory for your own project; the file-ranking shape is what generalizes.
- -l ts scopes the parser to TypeScript; use -l js, -l python, -l go, etc. for other languages — ast-grep ships grammars for 20+.
- $$$ matches zero-or-more argument nodes; use $A for exactly one captured argument if you need to inspect what was logged, not just count calls.
- Unlike ripgrep, this won't match `console.log` inside a comment or a template-literal string — that's the entire point, but it means it's not a drop-in rg replacement for free-text search.