Esegui un refactoring strutturale del codice
Questa guida mostra come chiedere a un agente di apportare una modifica meccanica su larga scala — un codemod, una migrazione API in blocco, un pattern che vuoi eliminare — usando la ricerca e la riscrittura strutturale, con la modifica preparata per la revisione prima che venga scritto alcunché.
ast_grep trova il codice in base alla forma. ast_edit lo riscrive. resolve conferma o scarta.
Prima di iniziare
Sezione intitolata “Prima di iniziare”Gli strumenti strutturali coprono le lingue che il grafo del codice analizza: Dart, JavaScript, TypeScript, TSX, PHP, Python, Rust, Zig, C, C++, Go, Java, Ruby, C#, Swift, Kotlin, R, Assembly, MATLAB e Ada. Richiedono che le grammatiche tree-sitter siano predisposte, cosa che in una build distribuita avviene sempre: una grammatica mancante blocca il server invece di degradare la ricerca.
Trova prima la forma
Sezione intitolata “Trova prima la forma”Non riscrivere mai qualcosa che non hai guardato. Chiedi all’agente di cercare:
Trova ogni punto in cui chiamiamo
dispose()su un nullable di cui abbiamo appena verificato che non sia null.
ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")L’output è file:line più il codice sorgente corrispondente per ogni occorrenza.
Cosa ti offre la sintassi dei pattern
Sezione intitolata “Cosa ti offre la sintassi dei pattern”| Token | Corrisponde |
|---|---|
$NAME |
Qualsiasi singolo nodo, catturato |
$$$NAME |
Qualsiasi sequenza di nodi adiacenti — argomenti, istruzioni |
$_ |
Qualsiasi cosa, catturata senza nome |
Quello che conta: un $NAME ripetuto deve catturare lo stesso testo.
if ($X != null) $X.dispose()trova una guardia che elimina ciò che ha verificato. Non trova if (a != null) b.dispose(), che di solito è il bug che stavi cercando. Nessuna ricerca testuale può esprimere questo.
Quando il pattern non trova nulla
Sezione intitolata “Quando il pattern non trova nulla”Due cose da provare, in ordine:
- Rendilo più piccolo.
foo($X)prima diif (a) { foo($X); }. Un pattern che non è codice valido da solo spesso non è il costrutto che intendevi. - Indica la lingua.
language:viene dedotto solo quandopathindica un singolo file.
Un pattern che nessun contesto di analisi accetta viene segnalato come non analizzabile: lo strumento lo dice, invece di riportare “nessuna corrispondenza” per qualcosa che non veniva letto affatto come sembra.
Riscrivi, e controlla prima di applicare
Sezione intitolata “Riscrivi, e controlla prima di applicare”ast_edit( pattern: "if ($X != null) $X.dispose()", rewrite: "$X?.dispose()", language: "dart",)Il risultato è una proposta:
(proposed) ast_edit: if ($X != null) $X.dispose() → $X?.dispose()12 replacements in 4 files: lib/features/a/x.dart (3) lib/features/b/y.dart (5) …Nothing has been written. Call resolve with edit_id "edit_1" and action"accept" to apply it, or "discard" to drop it.Non c’è ancora nulla su disco. Leggi l’elenco, controlla un paio delle occorrenze segnalate dalla ricerca, poi:
resolve(edit_id: "edit_1", action: "accept")oppure
resolve(edit_id: "edit_1", action: "discard")Verifica il tuo lavoro con il compilatore
Sezione intitolata “Verifica il tuo lavoro con il compilatore”Il senso di farlo in modo strutturale è che la modifica è ampia. Le modifiche ampie sono esattamente il punto in cui una riscrittura dall’aspetto plausibile rompe un tipo. Chiedi la diagnostica dopo aver eseguito resolve:
lsp(action: "diagnostics", file: "*")file: "*" esegue il checker del progetto (dart analyze, tsc --noEmit, cargo check, go build) invece di una query per singolo file: la forma giusta di domanda dopo una modifica che ha toccato quaranta file.
Esempio pratico: migrare una chiamata
Sezione intitolata “Esempio pratico: migrare una chiamata”Supponiamo che log(msg, level) stia diventando log(level: level, message: msg).
ast_grep(pattern: "log($MSG, $LEVEL)", language: "dart")Guarda le occorrenze. Se alcune sono un log a due argomenti diverso, restringi il pattern limitando path alla directory che contiene quello che intendi, invece di provare a esprimere la differenza nel pattern.
ast_edit( pattern: "log($MSG, $LEVEL)", rewrite: "log(level: $LEVEL, message: $MSG)", path: "lib/features/telemetry", language: "dart",)Poi resolve, quindi lsp(action: "diagnostics", file: "*").
Quando usare qualcos’altro
Sezione intitolata “Quando usare qualcos’altro”| Situazione | Strumento migliore |
|---|---|
| Rinominare un simbolo | lsp_rename — segue i riferimenti, non le forme |
| Trovare una stringa, un commento o un nome di file | search (contenuti) / search_files (nomi) |
| “Cosa si rompe se modifico questo?” | Il grafo del codice |
| Una lingua non coperta dalle grammatiche | search più edit |
Correlati
Sezione intitolata “Correlati”- Intelligence del codice — perché la corrispondenza strutturale non è una regex con qualche passaggio in più
- Strumenti agent integrati — l’elenco completo degli argomenti
- Cerca codice con il grafo del codice — il lato dei simboli e dell’impatto