Files
2025-11-30 09:06:54 +08:00

7.5 KiB

ast-grep Comprehensive Reference Guide

This guide provides comprehensive ast-grep knowledge for structural code search and transformation.

Core ast-grep Concepts

Pattern Syntax

  • Use actual code syntax for the target language
  • Use metavariables to capture patterns:
    • $VAR - matches any single AST node (expression, identifier, etc.)
    • $$$ARGS - matches multiple nodes (zero or more)
    • $$STMT - matches multiple statements

Basic Commands

# Search for pattern
ast-grep -p 'PATTERN'

# Specify language (always prefer explicit language)
ast-grep -l typescript -p 'PATTERN'

# Search and replace (preview)
ast-grep -p 'OLD_PATTERN' -r 'NEW_PATTERN'

# Apply changes (after verification)
ast-grep -p 'OLD_PATTERN' -r 'NEW_PATTERN' --update-all

# JSON output (for parsing)
ast-grep -p 'PATTERN' --json

CRITICAL CONSTRAINT: You cannot use interactive mode (-i) - you cannot respond to interactive prompts.


Recommended Workflow

1. Search Phase (Discovery)

# First, find matches to understand scope
ast-grep -l LANG -p 'PATTERN' [file_or_dir]

# Count matches to verify expectations
ast-grep -p 'PATTERN' | wc -l

2. Verification Phase (Before Changes)

  • Always run search first to see what will match
  • Review matches to ensure pattern is correct
  • Verify no false positives

3. Application Phase (Making Changes)

Two viable strategies:

Strategy A: Direct Application (for high confidence scenarios)

ast-grep -p 'OLD' -r 'NEW'  # Preview first
ast-grep -p 'OLD' -r 'NEW' --update-all  # Apply after thorough review

Strategy B: Hybrid Approach (RECOMMENDED for maximum control)

  1. Use ast-grep to find matches: ast-grep -l LANG -p 'PATTERN'
  2. Read the files to see actual context
  3. Use Edit tool to apply changes with precise control

This combines ast-grep's structural search with Edit's precision.

4. Validation Phase

# After changes, verify the new pattern exists
ast-grep -p 'NEW_PATTERN' [file_or_dir]

Common Use Cases with Examples

1. Function Call Refactoring

# Find all calls to a function
ast-grep -l typescript -p 'oldFunction($$$ARGS)'

# Replace with new function
ast-grep -l typescript -p 'oldFunction($$$ARGS)' -r 'newFunction($$$ARGS)'

2. Method Rename

# Find method calls on any object
ast-grep -l javascript -p '$OBJ.oldMethod($$$ARGS)' -r '$OBJ.newMethod($$$ARGS)'

3. Import Statement Changes

# TypeScript/JavaScript: change import source
ast-grep -l typescript -p 'import $WHAT from "old-package"' -r 'import $WHAT from "new-package"'

4. Adding Parameters to Function Calls

# Add a new parameter to all calls
ast-grep -l javascript -p 'doThing($ARG1, $ARG2)' -r 'doThing($ARG1, $ARG2, { new: true })'

5. Find Complex Patterns

# Find try-catch blocks with specific pattern
ast-grep -l javascript -p 'try { $$$BODY } catch ($ERR) { console.error($$$) }'

# Find async functions
ast-grep -l typescript -p 'async function $NAME($$$ARGS) { $$$BODY }'

6. Class Method Changes

# Find all methods in classes
ast-grep -l typescript -p 'class $CLASS { $$$A $METHOD($$$PARAMS) { $$$BODY } $$$B }'

Language-Specific Tips

JavaScript/TypeScript (-l typescript or -l javascript)

  • Works for: .js, .jsx, .ts, .tsx
  • Patterns use JS/TS syntax exactly as written
  • Arrow functions: ($$$ARGS) => $BODY
  • Always use -l typescript for TypeScript files

Python (-l python)

  • Indentation in pattern matters less than structure
  • Use Python syntax: def $NAME($$$ARGS):

Go (-l go)

  • Use Go syntax: func $NAME($$$ARGS) $RET { $$$ }
  • Package/import matching: import "$PKG"

Rust (-l rust)

  • Use Rust syntax: fn $NAME($$$ARGS) -> $RET { $$$ }
  • Match macros: println!($$$ARGS)

Best Practices

1. Always Verify Before Applying

# NEVER apply changes without seeing matches first
# BAD: ast-grep -p 'pattern' -r 'replacement' --update-all
# GOOD:
ast-grep -p 'pattern'  # Review matches
ast-grep -p 'pattern' -r 'replacement'  # Preview changes
ast-grep -p 'pattern' -r 'replacement' --update-all  # Apply only after review

2. Always Use Explicit Language Flag

# BAD: ast-grep -p 'pattern'  # May auto-detect incorrectly
# GOOD: ast-grep -l typescript -p 'pattern'  # Explicit and reliable

3. Start Specific, Broaden if Needed

  • Begin with very specific patterns
  • If no matches, gradually make pattern more general
  • Use metavariables for parts that vary, keep fixed parts specific

4. Use Metavariables Appropriately

  • $VAR - single expression (e.g., $X + $Y)
  • $$$ARGS - multiple items in lists (e.g., function arguments)
  • $$STMT - multiple statements (e.g., function body)

5. Combine with Other Tools

# Use ast-grep to find, pipe to other tools
ast-grep -p 'pattern' | rg -e 'additional-filter'

# Use ast-grep to find locations, then Edit to apply
ast-grep -l typescript -p 'pattern'  # Find matches
# Then use Edit tool with precise context

Common Pitfalls to Avoid

1. Overly Broad Patterns

ast-grep -p '$X' - matches everything ✓ ast-grep -l typescript -p 'specificFunction($X)' - targeted

2. Forgetting Language Flag

ast-grep -p 'pattern' - may misdetect language ✓ ast-grep -l typescript -p 'pattern' - explicit

3. Not Verifying Before --update-all

ast-grep -p 'old' -r 'new' --update-all - blind changes ✓ Preview first, verify matches, then apply

4. Expecting Exact Text Matching

ast-grep matches structure, not text:

  • foo( x ) and foo(x) are the same structurally
  • Line breaks don't matter in most cases
  • Comments are typically ignored

5. Using for Non-Code Files

ast-grep won't help with:

  • Markdown content
  • JSON/YAML values (not code structure)
  • Plain text files
  • Comments (usually)

Error Handling

If ast-grep fails or is unavailable:

  1. Fall back to text-based tools immediately
  2. Don't apologize excessively - just use the alternative approach

If pattern doesn't match:

  1. Verify language detection: ensure -l LANG is used
  2. Simplify pattern - start with minimal matching case
  3. Check syntax - ensure pattern is valid code for target language
  4. Fall back to Grep for discovery, then use Edit

If too many matches:

  1. Make pattern more specific
  2. Add context to pattern (surrounding code)
  3. Use directory/file path to narrow scope
  4. Consider using ast-grep for finding, Edit for selective changes

Integration with Edit Tool

When maximum control is needed:

  1. Use ast-grep to identify locations:
ast-grep -l typescript -p 'pattern'
  1. Read the matched files to see actual context

  2. Use Edit tool with precise old_string/new_string based on actual file content

This combines ast-grep's structural search with Edit's precise control. This is often the best approach because:

  • ast-grep finds the right locations structurally
  • Edit gives precise control over the exact changes
  • Each match can be handled differently if needed
  • Lower risk of unintended changes

Summary: Key Principles

  1. ast-grep solves the "not unique" problem by matching code structure instead of text
  2. Always verify before applying - search first, review matches, then apply
  3. Always use explicit language flag (-l typescript, -l python, etc.)
  4. Use metavariables correctly - $VAR for single nodes, $$$ARGS for multiple
  5. Consider hybrid approach - ast-grep for finding, Edit for applying
  6. Fall back gracefully - if ast-grep doesn't work, use text tools without hesitation