Back to skills
SkillHub ClubRun DevOpsFull StackSecurity

moai-tool-ast-grep

Integrates the ast-grep CLI for structural code search and transformation across 40+ languages. Enables pattern matching, security vulnerability detection, and automated refactoring using AST-based rules. Provides concrete examples for common use cases like finding console.log calls or detecting SQL injection patterns.

Packaged view

This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.

Stars
56
Hot score
92
Updated
March 20, 2026
Overall rating
A8.3
Composite score
6.2
Best-practice grade
N/A

Install command

npx @skill-hub/cli install modu-ai-cc-plugins-moai-tool-ast-grep
code-searchrefactoringsecurity-scanningstatic-analysismulti-language

Repository

modu-ai/cc-plugins

Skill path: .claude/skills/moai-tool-ast-grep

Integrates the ast-grep CLI for structural code search and transformation across 40+ languages. Enables pattern matching, security vulnerability detection, and automated refactoring using AST-based rules. Provides concrete examples for common use cases like finding console.log calls or detecting SQL injection patterns.

Open repository

Best for

Primary workflow: Run DevOps.

Technical facets: Full Stack, Security.

Target audience: Developers and engineering teams needing to perform large-scale codebase searches, security audits, or automated refactoring that regex cannot handle, particularly those working in polyglot environments..

License: Unknown.

Original source

Catalog source: SkillHub Club.

Repository owner: modu-ai.

This is still a mirrored public skill entry. Review the repository before installing into production workflows.

What it helps with

  • Install moai-tool-ast-grep into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
  • Review https://github.com/modu-ai/cc-plugins before adding moai-tool-ast-grep to shared team environments
  • Use moai-tool-ast-grep for development workflows

Works across

Claude CodeCodex CLIGemini CLIOpenCode

Favorites: 0.

Sub-skills: 0.

Aggregator: No.

Original source / Raw SKILL.md

---
name: "moai-tool-ast-grep"
description: "AST-based structural code search, security scanning, and refactoring using ast-grep (sg CLI). Supports 40+ languages with pattern matching and code transformation."
version: 1.0.0
category: "tool"
modularized: true
tags: ['ast', 'refactoring', 'code-search', 'lint', 'structural-search', 'security', 'codemod']
related-skills: ['moai-workflow-testing', 'moai-foundation-quality', 'moai-domain-backend', 'moai-domain-frontend']
updated: 2026-01-06
status: "active"
allowed-tools: "Read, Grep, Glob, Bash, mcp__context7__resolve-library-id, mcp__context7__get-library-docs"
---

# AST-Grep Integration

Structural code search, lint, and transformation tool using Abstract Syntax Tree analysis.

## Quick Reference (30 seconds)

### What is AST-Grep?

AST-Grep (sg) is a fast, polyglot tool for structural code search and transformation. Unlike regex-based search, it understands code syntax and matches patterns based on AST structure.

### When to Use

- Searching for code patterns that regex cannot capture (e.g., nested function calls)
- Refactoring code across multiple files with semantic awareness
- Security scanning for vulnerability patterns (SQL injection, XSS, etc.)
- API migration and deprecation handling
- Enforcing code style rules at the syntax level

### Core Commands

```bash
# Pattern search
sg run --pattern 'console.log($MSG)' --lang javascript src/

# Security scan with rules
sg scan --config sgconfig.yml

# Code transformation
sg run --pattern 'foo($A)' --rewrite 'bar($A)' --lang python src/

# Test rules
sg test
```

### Pattern Syntax Basics

```
$VAR       - Matches any single AST node (meta-variable)
$$$ARGS    - Matches zero or more nodes (variadic)
$$_        - Matches any single node (anonymous)
```

### Supported Languages

Python, JavaScript, TypeScript, Go, Rust, Java, Kotlin, C, C++, Ruby, Swift, C#, PHP, Scala, Elixir, Lua, HTML, Vue, Svelte, and 30+ more.

---

## Implementation Guide (5 minutes)

### Installation

```bash
# macOS
brew install ast-grep

# npm (cross-platform)
npm install -g @ast-grep/cli

# Cargo (Rust)
cargo install ast-grep
```

### Basic Pattern Matching

#### Simple Pattern Search

```bash
# Find all console.log calls
sg run --pattern 'console.log($MSG)' --lang javascript

# Find all Python function definitions
sg run --pattern 'def $FUNC($$$ARGS): $$$BODY' --lang python

# Find React useState hooks
sg run --pattern 'useState($INIT)' --lang typescriptreact
```

#### Meta-variables

Meta-variables capture matching AST nodes:

```yaml
# $NAME - Single node capture
pattern: 'const $NAME = require($PATH)'

# $$$ARGS - Variadic capture (zero or more)
pattern: 'function $NAME($$$ARGS) { $$$BODY }'

# $$_ - Anonymous single capture (don't care)
pattern: 'if ($$_) { return $VALUE }'
```

### Code Transformation

#### Simple Rewrite

```bash
# Rename function
sg run --pattern 'oldFunc($ARGS)' --rewrite 'newFunc($ARGS)' --lang python

# Update API call
sg run --pattern 'axios.get($URL)' --rewrite 'fetch($URL)' --lang typescript
```

#### Complex Transformation with YAML Rules

```yaml
# rule.yml
id: convert-var-to-const
language: javascript
rule:
  pattern: 'var $NAME = $VALUE'
fix: 'const $NAME = $VALUE'
message: 'Prefer const over var'
severity: warning
```

```bash
sg scan --rule rule.yml src/
```

### Rule-Based Scanning

#### Configuration File (sgconfig.yml)

```yaml
ruleDirs:
  - ./rules/security
  - ./rules/quality

testConfigs:
  - ./rules/**/__tests__/*.yml

languageGlobs:
  python: ['**/*.py']
  typescript: ['**/*.ts', '**/*.tsx']
  javascript: ['**/*.js', '**/*.jsx']
```

#### Security Rule Example

```yaml
# rules/security/sql-injection.yml
id: sql-injection-risk
language: python
severity: error
message: 'Potential SQL injection vulnerability. Use parameterized queries.'
rule:
  any:
    - pattern: 'cursor.execute($QUERY % $ARGS)'
    - pattern: 'cursor.execute($QUERY.format($$$ARGS))'
    - pattern: 'cursor.execute(f"$$$SQL")'
fix: 'cursor.execute($QUERY, $ARGS)'
```

### Relational Rules

#### Inside Rule (Scoped Search)

```yaml
id: no-console-in-function
language: javascript
rule:
  pattern: 'console.log($$$ARGS)'
  inside:
    pattern: 'function $NAME($$$PARAMS) { $$$BODY }'
```

#### Has Rule (Contains Check)

```yaml
id: async-without-await
language: javascript
rule:
  pattern: 'async function $NAME($$$PARAMS) { $$$BODY }'
  not:
    has:
      pattern: 'await $EXPR'
message: 'Async function without await'
```

#### Follows/Precedes Rules

```yaml
id: missing-error-handling
language: go
rule:
  pattern: '$ERR := $CALL'
  not:
    follows:
      pattern: 'if $ERR != nil { $$$BODY }'
```

### Composite Rules

```yaml
id: complex-rule
language: typescript
rule:
  all:
    - pattern: 'useState($INIT)'
    - inside:
        pattern: 'function $COMPONENT($$$PROPS) { $$$BODY }'
    - not:
        precedes:
          pattern: 'useEffect($$$ARGS)'
```

---

## Advanced Patterns

For comprehensive documentation including:
- Complex multi-file transformations
- Custom language configuration
- CI/CD integration patterns
- Performance optimization tips

See the following module files:

- [modules/pattern-syntax.md](modules/pattern-syntax.md) - Complete pattern syntax reference
- [modules/security-rules.md](modules/security-rules.md) - Security scanning rule templates
- [modules/refactoring-patterns.md](modules/refactoring-patterns.md) - Common refactoring patterns
- [modules/language-specific.md](modules/language-specific.md) - Language-specific patterns

### Context7 Integration

For latest AST-Grep documentation:

```
Step 1: Resolve library ID
Use mcp__context7__resolve-library-id with query "ast-grep"

Step 2: Fetch documentation
Use mcp__context7__get-library-docs with the resolved library ID
```

### MoAI-ADK Integration

AST-Grep is integrated into MoAI-ADK through:

1. **Tool Registry**: Registered as AST_ANALYZER type in `tool_registry.py`
2. **PostToolUse Hook**: Automatic security scanning after Write/Edit operations
3. **Permissions**: `Bash(sg:*)` and `Bash(ast-grep:*)` auto-allowed

### Running Scans

```bash
# Scan with MoAI-ADK rules
sg scan --config .claude/skills/moai-tool-ast-grep/rules/sgconfig.yml

# Scan specific directory
sg scan --config sgconfig.yml src/

# JSON output for CI/CD
sg scan --config sgconfig.yml --json > results.json
```

---

## Works Well With

- **moai-workflow-testing** - TDD integration, test pattern detection
- **moai-foundation-quality** - TRUST 5 compliance, code quality gates
- **moai-domain-backend** - API pattern detection, security scanning
- **moai-domain-frontend** - React/Vue pattern optimization
- **moai-lang-python** - Python-specific security and style rules
- **moai-lang-typescript** - TypeScript type safety patterns

### Related Agents

- **expert-refactoring** - AST-based large-scale refactoring
- **expert-security** - Security vulnerability scanning
- **manager-quality** - Code complexity analysis
- **expert-debug** - Pattern-based debugging

---

## Reference

- [AST-Grep Official Documentation](https://ast-grep.github.io/)
- [AST-Grep GitHub Repository](https://github.com/ast-grep/ast-grep)
- [Pattern Playground](https://ast-grep.github.io/playground.html)
- [Rule Configuration Reference](https://ast-grep.github.io/reference/yaml.html)


---

## Referenced Files

> The following files are referenced in this skill and included for context.

### modules/pattern-syntax.md

```markdown
# AST-Grep Pattern Syntax Reference

Complete guide to AST-Grep pattern matching syntax.

## Meta-Variables

### Single Node Capture ($NAME)

Captures exactly one AST node.

```yaml
# Match any function call with one argument
pattern: '$FUNC($ARG)'

# Examples matched:
# - print("hello")
# - len(items)
# - calculate(100)
```

### Variadic Capture ($$$NAME)

Captures zero or more AST nodes.

```yaml
# Match function with any number of arguments
pattern: 'function $NAME($$$ARGS) { $$$BODY }'

# Examples matched:
# - function foo() { return 1; }
# - function bar(a, b, c) { console.log(a); return b + c; }
```

### Anonymous Capture ($$_)

Matches any single node without capturing.

```yaml
# Match if statement regardless of condition
pattern: 'if ($$_) { return $VALUE }'

# Useful when you don't need the matched value
```

### Underscore Wildcard ($_)

Shorthand for anonymous single capture.

```yaml
pattern: '$_.$METHOD($$$ARGS)'
# Matches any method call on any object
```

## Relational Rules

### inside

Match pattern only within another pattern.

```yaml
id: useState-in-component
rule:
  pattern: 'useState($INIT)'
  inside:
    pattern: 'function $COMPONENT($$$PROPS) { $$$BODY }'
    stopBy: end  # Don't search nested functions
```

### has

Pattern must contain another pattern.

```yaml
id: class-with-constructor
rule:
  pattern: 'class $NAME { $$$BODY }'
  has:
    pattern: 'constructor($$$ARGS) { $$$IMPL }'
```

### follows

Pattern must be followed by another pattern.

```yaml
id: error-handling-required
rule:
  pattern: '$ERR := $CALL($$$ARGS)'
  follows:
    pattern: 'if $ERR != nil { $$$BODY }'
```

### precedes

Pattern must be preceded by another pattern.

```yaml
id: declaration-before-use
rule:
  pattern: '$VAR'
  precedes:
    pattern: 'const $VAR = $VALUE'
```

## Composite Rules

### all

All conditions must match.

```yaml
rule:
  all:
    - pattern: 'fetch($URL)'
    - inside:
        pattern: 'async function $NAME() { $$$BODY }'
    - not:
        has:
          pattern: 'try { $$$TRY } catch { $$$CATCH }'
```

### any

At least one condition must match.

```yaml
rule:
  any:
    - pattern: 'console.log($$$ARGS)'
    - pattern: 'console.warn($$$ARGS)'
    - pattern: 'console.error($$$ARGS)'
```

### not

Negates a condition.

```yaml
rule:
  pattern: 'async function $NAME() { $$$BODY }'
  not:
    has:
      pattern: 'await $EXPR'
```

## Stop-By Modifiers

Control how deeply rules search.

```yaml
rule:
  pattern: '$VAR'
  inside:
    pattern: 'function $NAME() { $$$BODY }'
    stopBy:
      rule:
        pattern: 'function $NESTED() { $$$INNER }'
```

Options:
- `end` - Stop at the end of matched node
- `neighbor` - Stop at immediate children
- `rule` - Stop when a specific rule matches

## Regex in Patterns

Use regex for identifier matching.

```yaml
rule:
  pattern: '$FUNC($$$ARGS)'
  constraints:
    FUNC:
      regex: '^(get|fetch|load).*'
```

## Fix Transformations

### Simple Fix

```yaml
fix: 'newFunction($ARGS)'
```

### Multi-line Fix

```yaml
fix: |
  try {
    $ORIGINAL
  } catch (error) {
    console.error(error);
  }
```

### Conditional Fix (via separate rules)

Create separate rules with different severity levels for different fixes.

## Examples

### Detect Deprecated API

```yaml
id: deprecated-substr
language: javascript
rule:
  pattern: '$STR.substr($$$ARGS)'
fix: '$STR.slice($$$ARGS)'
message: 'substr is deprecated, use slice instead'
```

### Enforce Error Handling

```yaml
id: unhandled-promise
language: typescript
rule:
  pattern: '$PROMISE.then($CALLBACK)'
  not:
    has:
      pattern: '.catch($HANDLER)'
message: 'Promise should have error handling'
```

### Security Pattern

```yaml
id: no-eval
language: javascript
severity: error
rule:
  any:
    - pattern: 'eval($CODE)'
    - pattern: 'new Function($$$ARGS)'
message: 'Avoid eval() and new Function() - potential code injection'
```

```

### modules/security-rules.md

```markdown
# AST-Grep Security Rules

Security vulnerability detection patterns for common attack vectors.

## SQL Injection

### Python

```yaml
id: sql-injection-python-format
language: python
severity: error
rule:
  any:
    - pattern: 'cursor.execute($QUERY % $ARGS)'
    - pattern: 'cursor.execute($QUERY.format($$$ARGS))'
    - pattern: 'cursor.execute(f"$$$SQL")'
    - pattern: 'execute($QUERY + $ARGS)'
message: 'Potential SQL injection. Use parameterized queries.'
fix: 'cursor.execute($QUERY, ($ARGS,))'
```

### JavaScript/TypeScript

```yaml
id: sql-injection-js
language: javascript
severity: error
rule:
  any:
    - pattern: '$DB.query(`$$$SQL ${$VAR} $$$REST`)'
    - pattern: '$DB.query($SQL + $VAR)'
    - pattern: '$DB.raw($SQL + $VAR)'
message: 'Potential SQL injection. Use parameterized queries.'
```

## XSS (Cross-Site Scripting)

### React

```yaml
id: xss-dangerouslySetInnerHTML
language: typescriptreact
severity: warning
rule:
  pattern: 'dangerouslySetInnerHTML={{ __html: $CONTENT }}'
  not:
    has:
      pattern: 'DOMPurify.sanitize($CONTENT)'
message: 'XSS risk: sanitize content before using dangerouslySetInnerHTML'
```

### JavaScript DOM

```yaml
id: xss-innerHTML
language: javascript
severity: warning
rule:
  any:
    - pattern: '$EL.innerHTML = $CONTENT'
    - pattern: 'document.write($CONTENT)'
message: 'Potential XSS vulnerability. Sanitize user input.'
```

## Secrets Detection

### Hardcoded Credentials

```yaml
id: hardcoded-password
language: python
severity: error
rule:
  any:
    - pattern: 'password = "$$$VALUE"'
    - pattern: 'PASSWORD = "$$$VALUE"'
    - pattern: 'secret = "$$$VALUE"'
    - pattern: 'api_key = "$$$VALUE"'
constraints:
  VALUE:
    regex: '.{8,}'  # At least 8 characters
message: 'Hardcoded credential detected. Use environment variables.'
```

### API Keys

```yaml
id: exposed-api-key
language: javascript
severity: error
rule:
  any:
    - pattern: 'apiKey: "$$$KEY"'
    - pattern: 'API_KEY = "$$$KEY"'
    - pattern: 'Authorization: "Bearer $$$TOKEN"'
message: 'API key should not be hardcoded. Use environment variables.'
```

## Command Injection

### Python

```yaml
id: command-injection-python
language: python
severity: error
rule:
  any:
    - pattern: 'os.system($CMD)'
    - pattern: 'subprocess.call($CMD, shell=True)'
    - pattern: 'subprocess.run($CMD, shell=True)'
    - pattern: 'os.popen($CMD)'
message: 'Potential command injection. Avoid shell=True and use subprocess with list arguments.'
fix: 'subprocess.run(shlex.split($CMD), shell=False)'
```

### JavaScript

```yaml
id: command-injection-js
language: javascript
severity: error
rule:
  any:
    - pattern: 'exec($CMD)'
    - pattern: 'execSync($CMD)'
    - pattern: 'spawn($CMD, { shell: true })'
message: 'Potential command injection. Use spawn with shell: false.'
```

## Path Traversal

```yaml
id: path-traversal
language: python
severity: error
rule:
  any:
    - pattern: 'open($PATH + $USER_INPUT)'
    - pattern: 'open(f"$$$PATH{$USER_INPUT}$$$REST")'
    - pattern: 'os.path.join($BASE, $USER_INPUT)'
  not:
    precedes:
      any:
        - pattern: 'os.path.realpath($$$ARGS)'
        - pattern: 'os.path.abspath($$$ARGS)'
message: 'Path traversal risk. Validate and sanitize file paths.'
```

## Insecure Cryptography

### Weak Hashing

```yaml
id: weak-hash-algorithm
language: python
severity: warning
rule:
  any:
    - pattern: 'hashlib.md5($$$ARGS)'
    - pattern: 'hashlib.sha1($$$ARGS)'
message: 'Weak hash algorithm. Use SHA-256 or stronger.'
fix: 'hashlib.sha256($$$ARGS)'
```

### Insecure Random

```yaml
id: insecure-random
language: python
severity: warning
rule:
  pattern: 'random.random()'
  inside:
    any:
      - pattern: 'def $FUNC($$$ARGS): $$$BODY'
        constraints:
          FUNC:
            regex: '.*(token|secret|key|password).*'
message: 'Use secrets module for security-sensitive random values.'
fix: 'secrets.token_hex(16)'
```

## CSRF Protection

```yaml
id: missing-csrf-token
language: html
severity: warning
rule:
  pattern: '<form $$$ATTRS>'
  not:
    has:
      pattern: 'csrf_token'
message: 'Form may be missing CSRF token.'
```

## Authentication Issues

### Hardcoded JWT Secret

```yaml
id: hardcoded-jwt-secret
language: javascript
severity: error
rule:
  pattern: 'jwt.sign($PAYLOAD, "$SECRET")'
message: 'JWT secret should not be hardcoded.'
```

### Missing Token Verification

```yaml
id: jwt-no-verification
language: javascript
severity: error
rule:
  pattern: 'jwt.decode($TOKEN)'
  not:
    inside:
      has:
        pattern: 'jwt.verify($TOKEN, $SECRET)'
message: 'Use jwt.verify() instead of jwt.decode() for security.'
```

## Usage

Run security scan:

```bash
sg scan --config .claude/skills/moai-tool-ast-grep/rules/sgconfig.yml --severity error
```

JSON output for CI:

```bash
sg scan --config sgconfig.yml --json | jq '.[] | select(.severity == "error")'
```

```

### modules/refactoring-patterns.md

```markdown
# AST-Grep Refactoring Patterns

Common code transformation patterns for large-scale refactoring.

## API Migration

### Function Rename

```bash
# Simple rename
sg run --pattern 'oldFunction($$$ARGS)' --rewrite 'newFunction($$$ARGS)' --lang python

# With method chain
sg run --pattern '$OBJ.oldMethod($$$ARGS)' --rewrite '$OBJ.newMethod($$$ARGS)' --lang javascript
```

### Library Migration

```yaml
# axios to fetch
id: axios-to-fetch-get
language: typescript
rule:
  pattern: 'axios.get($URL)'
fix: 'fetch($URL).then(res => res.json())'

---
id: axios-to-fetch-post
language: typescript
rule:
  pattern: 'axios.post($URL, $DATA)'
fix: |
  fetch($URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify($DATA)
  }).then(res => res.json())
```

### Import Statement Update

```yaml
id: update-import-path
language: typescript
rule:
  pattern: "import { $$$IMPORTS } from 'old-package'"
fix: "import { $$$IMPORTS } from '@new-scope/new-package'"
```

## Code Modernization

### var to const/let

```yaml
id: var-to-const
language: javascript
rule:
  pattern: 'var $NAME = $VALUE'
  not:
    has:
      pattern: '$NAME = $OTHER'
      inside:
        not:
          pattern: 'var $NAME = $VALUE'
fix: 'const $NAME = $VALUE'
message: 'Prefer const for variables that are never reassigned'
```

### Callback to Async/Await

```yaml
id: callback-to-async
language: javascript
rule:
  pattern: |
    $FUNC($$$ARGS, function($ERR, $DATA) {
      $$$BODY
    })
fix: |
  const $DATA = await $FUNC($$$ARGS)
  $$$BODY
message: 'Consider using async/await instead of callbacks'
```

### Promise.then to Async/Await

```yaml
id: then-to-await
language: typescript
rule:
  pattern: '$PROMISE.then($CALLBACK)'
  inside:
    pattern: 'async function $NAME($$$ARGS) { $$$BODY }'
fix: 'await $PROMISE'
```

## React Patterns

### Class to Functional Component

```yaml
id: class-to-functional-state
language: typescriptreact
rule:
  pattern: 'this.state.$PROP'
  inside:
    pattern: 'class $NAME extends $$$BASE { $$$BODY }'
message: 'Consider converting to functional component with useState'
```

### componentDidMount to useEffect

```yaml
id: componentDidMount-to-useEffect
language: typescriptreact
rule:
  pattern: |
    componentDidMount() {
      $$$BODY
    }
fix: |
  useEffect(() => {
    $$$BODY
  }, [])
```

### PropTypes to TypeScript

```yaml
id: proptypes-to-typescript
language: typescriptreact
rule:
  pattern: '$COMPONENT.propTypes = { $$$PROPS }'
message: 'Consider using TypeScript interfaces instead of PropTypes'
```

## Python Patterns

### String Format to f-string

```yaml
id: format-to-fstring
language: python
rule:
  pattern: '"$$$STR".format($ARG)'
fix: 'f"$$$STR"'  # Note: requires manual adjustment of placeholders
message: 'Consider using f-strings for cleaner formatting'
```

### Dict Comprehension

```yaml
id: loop-to-dict-comprehension
language: python
rule:
  pattern: |
    $DICT = {}
    for $KEY in $ITER:
        $DICT[$KEY] = $VALUE
fix: '$DICT = {$KEY: $VALUE for $KEY in $ITER}'
```

### Context Manager

```yaml
id: file-to-context-manager
language: python
rule:
  pattern: |
    $FILE = open($PATH)
    $$$BODY
    $FILE.close()
fix: |
  with open($PATH) as $FILE:
      $$$BODY
```

## Go Patterns

### Error Handling

```yaml
id: error-wrap
language: go
rule:
  pattern: 'return $ERR'
  inside:
    pattern: 'if $ERR != nil { $$$BODY }'
fix: 'return fmt.Errorf("$FUNC: %w", $ERR)'
message: 'Wrap errors with context'
```

### Defer Pattern

```yaml
id: close-without-defer
language: go
rule:
  pattern: '$RESOURCE.Close()'
  not:
    inside:
      pattern: 'defer $RESOURCE.Close()'
message: 'Consider using defer for resource cleanup'
```

## TypeScript Patterns

### Type Assertion

```yaml
id: type-assertion-style
language: typescript
rule:
  pattern: '<$TYPE>$EXPR'
fix: '$EXPR as $TYPE'
message: 'Prefer "as" syntax for type assertions'
```

### Optional Chaining

```yaml
id: use-optional-chaining
language: typescript
rule:
  pattern: '$OBJ && $OBJ.$PROP'
fix: '$OBJ?.$PROP'
```

### Nullish Coalescing

```yaml
id: use-nullish-coalescing
language: typescript
rule:
  pattern: '$VAR !== null && $VAR !== undefined ? $VAR : $DEFAULT'
fix: '$VAR ?? $DEFAULT'
```

## Batch Refactoring

### Multi-file Transformation

```bash
# Find all files
sg run --pattern '$OLD($$$ARGS)' --lang python src/

# Preview changes
sg run --pattern '$OLD($$$ARGS)' --rewrite '$NEW($$$ARGS)' --lang python src/ --interactive

# Apply changes
sg run --pattern '$OLD($$$ARGS)' --rewrite '$NEW($$$ARGS)' --lang python src/ --update-all
```

### JSON Output for Review

```bash
sg scan --config rules.yml --json > changes.json
# Review changes before applying
cat changes.json | jq '.[] | {file: .path, line: .range.start.line, fix: .fix}'
```

```

### modules/language-specific.md

```markdown
# Language-Specific AST-Grep Patterns

Optimized patterns for specific programming languages.

## Python

### Type Hints

```yaml
id: missing-return-type
language: python
rule:
  pattern: 'def $FUNC($$$ARGS):'
  not:
    pattern: 'def $FUNC($$$ARGS) -> $TYPE:'
message: 'Function missing return type annotation'

---
id: missing-param-types
language: python
rule:
  pattern: 'def $FUNC($PARAM):'
  constraints:
    PARAM:
      not:
        regex: '.*:.*'  # No type annotation
message: 'Parameter missing type annotation'
```

### Async Patterns

```yaml
id: sync-in-async
language: python
rule:
  pattern: 'time.sleep($DURATION)'
  inside:
    pattern: 'async def $FUNC($$$ARGS): $$$BODY'
fix: 'await asyncio.sleep($DURATION)'
message: 'Use asyncio.sleep in async functions'

---
id: blocking-io-in-async
language: python
rule:
  any:
    - pattern: 'open($PATH)'
    - pattern: 'requests.get($URL)'
  inside:
    pattern: 'async def $FUNC($$$ARGS): $$$BODY'
message: 'Blocking I/O in async function. Use aiofiles or aiohttp.'
```

### Exception Handling

```yaml
id: bare-except
language: python
severity: warning
rule:
  pattern: |
    except:
        $$$BODY
fix: |
  except Exception as e:
      $$$BODY
message: 'Avoid bare except clauses'

---
id: exception-pass
language: python
rule:
  pattern: |
    except $EXC:
        pass
message: 'Silent exception handling - consider logging'
```

## TypeScript

### Type Safety

```yaml
id: any-type-usage
language: typescript
severity: warning
rule:
  any:
    - pattern: 'const $NAME: any = $VALUE'
    - pattern: 'let $NAME: any = $VALUE'
    - pattern: 'function $FUNC($$$ARGS): any'
message: 'Avoid using "any" type - be more specific'

---
id: type-assertion-warning
language: typescript
rule:
  pattern: '$EXPR as any'
message: 'Type assertion to "any" bypasses type checking'
```

### React Best Practices

```yaml
id: missing-key-prop
language: typescriptreact
rule:
  pattern: '$ARR.map($ITEM => <$COMPONENT $$$PROPS />)'
  not:
    has:
      pattern: 'key={$KEY}'
message: 'Missing key prop in list rendering'

---
id: inline-function-in-jsx
language: typescriptreact
rule:
  pattern: '<$COMPONENT onClick={() => $$$BODY} />'
message: 'Avoid inline functions in JSX - may cause unnecessary re-renders'

---
id: direct-state-mutation
language: typescriptreact
rule:
  pattern: '$STATE.$PROP = $VALUE'
  inside:
    has:
      pattern: 'useState($INIT)'
message: 'Do not mutate state directly - use setState'
```

### Next.js Patterns

```yaml
id: use-next-image
language: typescriptreact
rule:
  pattern: '<img $$$ATTRS />'
fix: '<Image $$$ATTRS />'
message: 'Use next/image for optimized images'

---
id: use-next-link
language: typescriptreact
rule:
  pattern: '<a href="$URL">$$$CHILDREN</a>'
  constraints:
    URL:
      not:
        regex: '^https?://.*'  # External links are OK
fix: '<Link href="$URL">$$$CHILDREN</Link>'
message: 'Use next/link for internal navigation'
```

## Go

### Error Handling

```yaml
id: unchecked-error
language: go
severity: error
rule:
  pattern: '$RESULT, _ := $FUNC($$$ARGS)'
message: 'Error ignored - handle or explicitly ignore with comment'

---
id: error-string-comparison
language: go
rule:
  pattern: 'err.Error() == "$MSG"'
message: 'Use errors.Is() or errors.As() for error comparison'
```

### Concurrency

```yaml
id: goroutine-leak
language: go
rule:
  pattern: 'go $FUNC($$$ARGS)'
  not:
    inside:
      has:
        any:
          - pattern: 'ctx.Done()'
          - pattern: 'select { $$$CASES }'
message: 'Goroutine may leak - ensure proper cancellation'

---
id: mutex-not-deferred
language: go
rule:
  pattern: '$MU.Lock()'
  not:
    follows:
      pattern: 'defer $MU.Unlock()'
message: 'Consider using defer for Unlock()'
```

### Context Usage

```yaml
id: context-first-param
language: go
rule:
  pattern: 'func $FUNC($$$BEFORE, ctx context.Context, $$$AFTER)'
message: 'Context should be the first parameter'
fix: 'func $FUNC(ctx context.Context, $$$BEFORE, $$$AFTER)'
```

## Rust

### Memory Safety

```yaml
id: unsafe-block
language: rust
severity: warning
rule:
  pattern: 'unsafe { $$$BODY }'
message: 'Unsafe block - ensure memory safety is manually verified'

---
id: unwrap-usage
language: rust
rule:
  any:
    - pattern: '$RESULT.unwrap()'
    - pattern: '$OPTION.unwrap()'
message: 'Consider using ? operator or expect() with message'
```

### Ownership Patterns

```yaml
id: clone-in-loop
language: rust
rule:
  pattern: '$VAR.clone()'
  inside:
    any:
      - pattern: 'for $ITEM in $ITER { $$$BODY }'
      - pattern: 'while $COND { $$$BODY }'
message: 'Clone in loop may be inefficient - consider borrowing'
```

## Java

### Resource Management

```yaml
id: resource-not-closed
language: java
rule:
  pattern: '$TYPE $VAR = new $RESOURCE($$$ARGS)'
  not:
    any:
      - inside:
          pattern: 'try ($TYPE $VAR = new $RESOURCE($$$ARGS)) { $$$BODY }'
      - follows:
          pattern: '$VAR.close()'
message: 'Resource may not be closed - use try-with-resources'
```

### Null Safety

```yaml
id: null-check-pattern
language: java
rule:
  pattern: 'if ($OBJ != null) { $$$BODY }'
message: 'Consider using Optional for null handling'

---
id: string-equals
language: java
rule:
  pattern: '$STR.equals($OTHER)'
  not:
    precedes:
      pattern: 'if ($STR != null)'
message: 'Potential NPE - use Objects.equals() or check for null'
fix: 'Objects.equals($STR, $OTHER)'
```

## Language Detection

AST-Grep auto-detects language from file extension:

```bash
# Explicit language specification
sg run --pattern '$PATTERN' --lang python

# Auto-detection (uses file extension)
sg run --pattern '$PATTERN' src/main.py

# Multiple languages
sg run --pattern '$PATTERN' --lang python --lang javascript
```

Supported language identifiers:
- `python`, `javascript`, `typescript`, `typescriptreact`
- `go`, `rust`, `java`, `kotlin`, `scala`
- `c`, `cpp`, `csharp`, `swift`
- `ruby`, `php`, `elixir`, `lua`
- `html`, `css`, `json`, `yaml`

```

### rules/security/sql-injection.yml

```yaml
# SQL Injection Detection Rules

id: sql-injection-python-format
language: python
severity: error
message: "Potential SQL injection: Use parameterized queries instead of string formatting"
rule:
  any:
    - pattern: cursor.execute($QUERY % $ARGS)
    - pattern: cursor.execute($QUERY.format($$$ARGS))
    - pattern: cursor.execute(f"$$$SQL")
    - pattern: execute($QUERY + $VAR)

---
id: sql-injection-python-fstring
language: python
severity: error
message: "Potential SQL injection: f-strings in SQL queries are dangerous"
rule:
  pattern: |
    cursor.execute(f"$$$SQL")

---
id: sql-injection-js-template
language: javascript
severity: error
message: "Potential SQL injection: Use parameterized queries"
rule:
  any:
    - pattern: $DB.query(`$$$SQL ${$VAR} $$$REST`)
    - pattern: $DB.query($SQL + $VAR)
    - pattern: $DB.raw($SQL + $VAR)
    - pattern: knex.raw($SQL + $VAR)

---
id: sql-injection-ts-template
language: typescript
severity: error
message: "Potential SQL injection: Use parameterized queries"
rule:
  any:
    - pattern: $DB.query(`$$$SQL ${$VAR} $$$REST`)
    - pattern: $DB.query($SQL + $VAR)
    - pattern: prisma.$raw($SQL + $VAR)
    - pattern: knex.raw($SQL + $VAR)

```

moai-tool-ast-grep | SkillHub