Skip to main content

ast-grep-search

Find and replace code patterns structurally with ast-grep. Use when matching code by AST structure, finding functions with specific signatures, or detecting anti-patterns regex cannot match.

Informations de source

Dépôt
laurigates/claude-plugins
Dernière activité de la source
26 septembre 2026 à 23:17
Langue détectée de SKILL.md
anglais
Étoiles
60
Forks
6

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
2 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
created
2025-12-16T00:00:00.000Z
modified
2026-09-25T00:00:00.000Z
reviewed
2026-04-25T00:00:00.000Z
name
ast-grep-search
description
Find and replace code patterns structurally with ast-grep. Use when matching code by AST structure, finding functions with specific signatures, or detecting anti-patterns regex cannot match.
user-invocable
false
allowed-tools
Bash(sg *), Bash(ast-grep *), Read, Grep, Glob
effort
low
# ast-grep Structural Code Search & Refactoring Structural code search and refactoring using `ast-grep` — matches code by its AST (abstract syntax tree) rather than text patterns. ## When to Use This Skill | Use this skill when... | Use something else instead when... | |------------------------|------------------------------------| | The pattern depends on AST structure (function shape, call form, argument count) | Searching plain text or regex matches → `tools-plugin:rg-code-search` | | Refactoring API call sites across many files while preserving captured variables | Running a one-shot anti-pattern scan with a report → `code-antipatterns` | | Hand-written structural search/replace for an ad-hoc migration | Functional refactors of a known file/directory → `code-refactor` | | Building a new ast-grep rule for a codebase-specific smell | Looking up agentic flags for an existing linter → `code-lint` | ## When to Use ast-grep vs Grep/ripgrep | Use ast-grep when... | Use grep/rg when... | |---------------------|---------------------| | Pattern depends on code structure | Simple text or regex match | | Need to match any number of arguments | Searching logs, docs, config | | Refactoring across many files | One-off literal string search | | Finding anti-patterns (empty catch, etc.) | Language doesn't matter | | Replacing while preserving variables | Quick filename/line check | **Decision rule**: If your search pattern contains wildcards for "any expression," "any arguments," or "any function name," use ast-grep. ## Find References With the Sharpest Instrument Promoted from `~/.claude/rules/tool-use-patterns.md`. `Edit` refuses on a file unread this session, so "read it first" is already a harness invariant. The **uncovered** half is checking what *else* depends on what you're changing, and the reflex there is `grep`, which cannot tell a call from a comment, a definition from a mention, or `foo()` from `"foo"` in a string. Measured across 282 local sessions: ~2,400 code-symbol searches went through `grep`/`rg`, against **6** `ast-grep` calls and **6** `LSP` calls. Ladder, sharpest first. Falling back down it is normal; starting at the bottom for a code symbol is the miss. | Reach for | When | |---|---| | `LSP` — `findReferences`, `incomingCalls`, `goToDefinition` | A language server is running for that filetype. Exact: no comment/string hits, and it follows imports and re-exports that no text pattern can. | | `ast-grep -p '$FN($$$ARGS)'` | No LSP, or the target is a *shape* rather than a name — a call with a given arity, a decorator, an un-awaited async call. Cross-language, bash included. | | `rg` | Non-code: markdown rules, chezmoi templates, config keys, justfile recipes, workflow YAML. The right tool there, not a fallback — most of a dotfiles or plugins repo is prose. | Two things that make the middle rung less automatic than it looks. A **bare identifier pattern matches the definition too** (`ast-grep --lang bash -p 'foo'` returns `foo() { … }` alongside every call), so an unshaped pattern is just `grep` with extra syntax. And a language server has to be **on `PATH`**, not merely installed — `bash-language-server` sitting in `~/.local/share/nvim/mason/bin` is invisible to the `LSP` tool, which silently drops shell to the middle rung. Structural tools carry their own empty-result trap: an `ast-grep` pattern that fails to parse returns no matches and exit 0, indistinguishable from a clean tree. Control-test the negative against a term you know is present, in the tool you are actually using (`agent-patterns-plugin:tool-result-traps`). ## Pattern Syntax | Pattern | Matches | Example | |---------|---------|---------| | `$VAR` | Single AST node | `console.log($MSG)` | | `$$$ARGS` | Zero or more nodes | `func($$$ARGS)` | | `$_` | Single node (no capture) | `$_ == $_` | | `$A == $A` | Same node repeated | Finds `x == x` (not `x == y`) | ## Essential Commands ### Search for Patterns ```bash # Find structural patterns ast-grep -p 'console.log($$$)' --lang js ast-grep -p 'def $FUNC($$$): $$$' --lang py ast-grep -p 'fn $NAME($$$) -> $RET { $$$ }' --lang rs # Search in specific directory ast-grep -p 'import $PKG' --lang js src/ # JSON output for parsing ast-grep -p 'pattern' --lang js --json=compact ``` ### Search and Replace ```bash # Preview changes (default - shows matches) ast-grep -p 'var $V = $X' -r 'const $V = $X' --lang js # Apply changes to all files ast-grep -p 'var $V = $X' -r 'const $V = $X' --lang js -U # Interactive review ast-grep -p 'oldAPI($$$ARGS)' -r 'newAPI($$$ARGS)' --lang py -i # Convert function syntax ast-grep -p 'function($$$ARGS) { return $EXPR }' \ -r '($$$ARGS) => $EXPR' --lang js -U # Update import paths ast-grep -p "import $NAME from '@old/$PATH'" \ -r "import $NAME from '@new/$PATH'" --lang ts -U ``` ### Language Codes | Code | Language | Code | Language | |------|----------|------|----------| | `js` | JavaScript | `py` | Python | | `ts` | TypeScript | `rs` | Rust | | `jsx` | JSX | `go` | Go | | `tsx` | TSX | `java` | Java | | `cpp` | C++ | `rb` | Ruby | | `c` | C | `php` | PHP | ## Common Patterns by Language ### JavaScript/TypeScript ```bash # Find React hooks ast-grep -p 'const [$STATE, $SETTER] = useState($INIT)' --lang jsx # Find async functions ast-grep -p 'async function $NAME($$$) { $$$ }' --lang js # Find type assertions ast-grep -p '$EXPR as $TYPE' --lang ts # Find empty catch blocks ast-grep -p 'try { $$$ } catch ($E) { }' --lang js # Find eval usage (security) ast-grep -p 'eval($$$)' --lang js # Find innerHTML (XSS risk) ast-grep -p '$ELEM.innerHTML = $$$' --lang js # Find specific imports ast-grep -p "import { $$$IMPORTS } from '$PKG'" --lang js ``` ### Python ```bash # Find class definitions ast-grep -p 'class $NAME($$$BASES): $$$' --lang py # Find decorated functions ast-grep -p '@$DECORATOR\ndef $FUNC($$$): $$$' --lang py # Find dangerous shell calls ast-grep -p 'os.system($$$)' --lang py # Find SQL concatenation (injection risk) ast-grep -p '"SELECT * FROM " + $VAR' --lang py ``` ### Rust ```bash # Find unsafe blocks ast-grep -p 'unsafe { $$$ }' --lang rs # Find impl blocks ast-grep -p 'impl $TRAIT for $TYPE { $$$ }' --lang rs # Find public functions ast-grep -p 'pub fn $NAME($$$) { $$$ }' --lang rs ``` ### Go ```bash # Find goroutines ast-grep -p 'go $FUNC($$$)' --lang go # Find defer statements ast-grep -p 'defer $FUNC($$$)' --lang go # Find error handling ast-grep -p 'if err != nil { $$$ }' --lang go ``` ## Common Refactoring Recipes ```bash # Replace deprecated API calls ast-grep -p 'oldAPI.$METHOD($$$)' -r 'newAPI.$METHOD($$$)' --lang js -U # Rename a function across files ast-grep -p 'oldName($$$ARGS)' -r 'newName($$$ARGS)' --lang py -U # Remove console.log statements ast-grep -p 'console.log($$$)' -r '' --lang js -U # Convert require to import ast-grep -p 'const $NAME = require($PKG)' \ -r 'import $NAME from $PKG' --lang js -i # Add error handling wrapper ast-grep -p 'await $EXPR' \ -r 'await $EXPR.catch(handleError)' --lang ts -i ``` ## Command-Line Flags | Flag | Purpose | |------|---------| | `-p, --pattern` | Search pattern | | `-r, --rewrite` | Replacement pattern | | `-l, --lang` | Target language | | `-i, --interactive` | Review changes one by one | | `-U, --update-all` | Apply all changes | | `--json` | JSON output (`compact`, `stream`, `pretty`) | | `-A N` | Lines after match | | `-B N` | Lines before match | | `-C N` | Lines around match | | `--debug-query` | Debug pattern parsing | ## YAML Rules (Scan Mode) For reusable rules, use `ast-grep scan` with YAML configuration: ```bash # Scan with config ast-grep scan -c sgconfig.yml # Run specific rule ast-grep scan -r rule-name # Initialize a rules project ast-grep new project my-linter ast-grep new rule no-console-log ``` Minimal rule file: ```yaml id: no-empty-catch language: JavaScript severity: warning message: Empty catch block hides errors rule: pattern: try { $$$ } catch ($E) { } fix: | try { $$$ } catch ($E) { console.error($E) } ``` For comprehensive YAML rule syntax, constraints, transformations, and testing, see [REFERENCE.md](REFERENCE.md). ## Agentic Optimizations | Context | Command | |---------|---------| | Quick structural search | `ast-grep -p 'pattern' --lang js --json=compact` | | Count matches | `ast-grep -p 'pattern' --lang js --json=stream \| wc -l` | | File list only | `ast-grep -p 'pattern' --json=stream \| jq -r '.file' \| sort -u` | | Batch refactor | `ast-grep -p 'old' -r 'new' --lang js -U` | | Scan with rules | `ast-grep scan --json` | | Debug pattern | `ast-grep -p 'pattern' --debug-query --lang js` | ## Quick Reference ```bash # 1. Search for pattern ast-grep -p 'pattern' --lang js src/ # 2. Preview rewrite ast-grep -p 'old' -r 'new' --lang js # 3. Apply rewrite ast-grep -p 'old' -r 'new' --lang js -U # 4. Scan with rules ast-grep scan -c sgconfig.yml # 5. Debug pattern ast-grep -p 'pattern' --debug-query --lang js ```
Voir sur GitHub