Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

AST Transforms

AST transforms modify code with awareness of its syntactic structure, using tree-sitter for parsing.

Note: AST transforms in the current version are primarily used for matching and analysis. For structural code modifications, consider using LSP-based refactoring which provides semantic understanding.

Basic Usage

#![allow(unused)]
fn main() {
use refactor::prelude::*;

Refactor::in_repo("./project")
    .transform(|t| t
        .ast(|a| a
            .query("(function_item name: (identifier) @fn)")
            .transform(|node| /* modify */)))
    .apply()?;
}

AstTransform Builder

The AstTransform type allows configuring AST-based transformations:

#![allow(unused)]
fn main() {
let transform = AstTransform::new()
    .query("(function_item name: (identifier) @fn)")
    .language(&Rust);
}

Query-Based Matching

AST transforms start with a tree-sitter query to identify code patterns:

#![allow(unused)]
fn main() {
// Find all function definitions
.query("(function_item name: (identifier) @fn)")

// Find struct definitions
.query("(struct_item name: (type_identifier) @struct)")

// Find method calls
.query("(call_expression
    function: (field_expression field: (field_identifier) @method))")
}

Common Patterns

Finding Functions

#![allow(unused)]
fn main() {
// Rust
"(function_item name: (identifier) @fn)"

// TypeScript
"(function_declaration name: (identifier) @fn)"

// Python
"(function_definition name: (identifier) @fn)"
}

Finding Classes/Structs

#![allow(unused)]
fn main() {
// Rust
"(struct_item name: (type_identifier) @name)"
"(impl_item type: (type_identifier) @impl_type)"

// TypeScript
"(class_declaration name: (type_identifier) @class)"

// Python
"(class_definition name: (identifier) @class)"
}

Finding Imports

#![allow(unused)]
fn main() {
// Rust
"(use_declaration argument: (_) @import)"

// TypeScript
"(import_statement source: (string) @source)"

// Python
"(import_statement name: (dotted_name) @import)"
}

Integration with Text Transforms

AST matching can identify locations for text-based replacement:

#![allow(unused)]
fn main() {
use refactor::prelude::*;

fn rename_function(source: &str, old_name: &str, new_name: &str) -> Result<String> {
    // First, find all occurrences using AST
    let matcher = AstMatcher::new()
        .query("(function_item name: (identifier) @fn)")
        .query("(call_expression function: (identifier) @call)");

    let matches = matcher.find_matches(source, &Rust)?;

    // Filter to our target function
    let target_matches: Vec<_> = matches
        .iter()
        .filter(|m| m.text == old_name)
        .collect();

    // Apply text replacement at those positions
    let mut result = source.to_string();
    for m in target_matches.iter().rev() {
        result.replace_range(m.start_byte..m.end_byte, new_name);
    }

    Ok(result)
}
}

Combining with File Matching

#![allow(unused)]
fn main() {
Refactor::in_repo("./project")
    .matching(|m| m
        .files(|f| f
            .extension("rs")
            .exclude("**/target/**"))
        .ast(|a| a
            .query("(function_item) @fn")))
    .transform(|t| t
        .replace_pattern(r"fn (\w+)", "pub fn $1"))
    .apply()?;
}

Language Detection

AST transforms require knowing the source language:

#![allow(unused)]
fn main() {
// Explicit language
let transform = AstTransform::new()
    .query("(function_item @fn)")
    .language(&Rust);

// Or detect from file extension
let registry = LanguageRegistry::new();
let lang = registry.detect(Path::new("file.rs")).unwrap();
}

Limitations

Current AST transform limitations:

  1. Read-only analysis - AST queries find patterns but don’t directly modify the tree
  2. No semantic understanding - Doesn’t understand types, scopes, or references
  3. Single-file scope - Can’t follow imports or understand project structure

For semantic refactoring (cross-file renames, reference updates), use LSP integration.

Future Directions

Planned enhancements:

  • Direct AST node manipulation
  • Structural search and replace
  • Code generation from AST templates
  • Multi-file AST analysis

See Also