Refaktor kod secara struktur
Panduan ini menunjukkan cara meminta ejen membuat perubahan mekanikal yang luas — codemod, penghijrahan API secara pukal, corak yang anda mahu hapuskan — menggunakan carian dan penulisan semula struktur, dengan perubahan itu diperingkatkan untuk semakan sebelum apa-apa ditulis.
ast_grep memadankan kod mengikut bentuk. ast_edit menulis semulanya. resolve mengkomit atau membuangnya.
Sebelum anda bermula
Bahagian bertajuk “Sebelum anda bermula”Alat struktur merangkumi bahasa yang dihuraikan oleh graf kod: Dart, JavaScript, TypeScript, TSX, PHP, Python, Rust, Zig, C, C++, Go, Java, Ruby, C#, Swift, Kotlin, R, Assembly, MATLAB dan Ada. Ia memerlukan tatabahasa tree-sitter disediakan, dan ia sentiasa begitu dalam binaan yang dikeluarkan — tatabahasa yang hilang menghentikan pelayan dan bukannya merendahkan carian.
Cari bentuk dahulu
Bahagian bertajuk “Cari bentuk dahulu”Jangan sekali-kali menulis semula sesuatu yang belum anda lihat. Minta ejen mencari:
Cari setiap tempat kita memanggil
dispose()pada nilai nullable yang baru sahaja kita semak null.
ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")Outputnya ialah file:line serta sumber yang dipadankan bagi setiap tapak.
Apa yang sintaks corak berikan kepada anda
Bahagian bertajuk “Apa yang sintaks corak berikan kepada anda”| Token | Padanan |
|---|---|
$NAME |
Sebarang nod tunggal, ditangkap |
$$$NAME |
Sebarang jujukan nod bersaudara — argumen, penyataan |
$_ |
Apa-apa sahaja, ditangkap tanpa nama |
Yang paling penting: $NAME yang berulang mesti menangkap teks yang sama.
if ($X != null) $X.dispose()menemui pengawal yang melupuskan apa yang diujinya. Ia tidak menemui if (a != null) b.dispose() — yang selalunya menjadi pepijat yang anda cari. Tiada carian teks dapat menyatakan perkara itu.
Apabila corak tidak menemui apa-apa
Bahagian bertajuk “Apabila corak tidak menemui apa-apa”Dua perkara untuk dicuba, mengikut urutan:
- Kecilkan ia.
foo($X)sebelumif (a) { foo($X); }. Corak yang bukan kod sah dengan sendirinya selalunya bukan konstruk yang anda maksudkan. - Namakan bahasa.
language:hanya diinferensikan apabilapathmenamakan satu fail tunggal.
Corak yang tidak diterima oleh mana-mana konteks penghuraian dilaporkan sebagai tidak boleh dihuraikan — alat itu menyatakannya dan bukannya melaporkan “tiada padanan” bagi sesuatu yang tidak pernah dibaca seperti rupanya.
Tulis semula, dan lihat sebelum ia mendarat
Bahagian bertajuk “Tulis semula, dan lihat sebelum ia mendarat”ast_edit( pattern: "if ($X != null) $X.dispose()", rewrite: "$X?.dispose()", language: "dart",)Hasilnya ialah satu cadangan:
(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.Belum ada apa-apa di cakera. Baca senarai itu, semak beberapa tapak yang dilaporkan oleh carian, kemudian:
resolve(edit_id: "edit_1", action: "accept")atau
resolve(edit_id: "edit_1", action: "discard")Semak kerja anda dengan pengkompil
Bahagian bertajuk “Semak kerja anda dengan pengkompil”Tujuan melakukannya secara struktur ialah kerana ia luas. Perubahan luas ialah tempat yang tepat apabila penulisan semula yang kelihatan munasabah memecahkan sesuatu jenis. Minta diagnostik selepas melakukan resolve:
lsp(action: "diagnostics", file: "*")file: "*" menjalankan pemeriksa projek itu sendiri (dart analyze, tsc --noEmit, cargo check, go build) dan bukannya pertanyaan bagi setiap fail — bentuk soalan yang betul selepas perubahan yang menyentuh empat puluh fail.
Contoh amali: menghijrahkan satu panggilan
Bahagian bertajuk “Contoh amali: menghijrahkan satu panggilan”Katakan log(msg, level) sedang bertukar menjadi log(level: level, message: msg).
ast_grep(pattern: "log($MSG, $LEVEL)", language: "dart")Lihat padanan yang ditemui. Jika sebahagian daripadanya ialah log dua argumen yang berbeza, sempitkan corak itu dengan menskopkan path kepada direktori yang memiliki log yang anda maksudkan, dan bukannya cuba menyatakan perbezaan itu dalam corak.
ast_edit( pattern: "log($MSG, $LEVEL)", rewrite: "log(level: $LEVEL, message: $MSG)", path: "lib/features/telemetry", language: "dart",)Kemudian resolve, kemudian lsp(action: "diagnostics", file: "*").
Bila perlu guna sesuatu yang lain
Bahagian bertajuk “Bila perlu guna sesuatu yang lain”| Keadaan | Alat yang lebih baik |
|---|---|
| Menamakan semula simbol | lsp_rename — ia mengikut rujukan, bukan bentuk |
| Mencari rentetan, komen atau nama fail | search (kandungan) / search_files (nama) |
| “Apa yang pecah jika saya ubah ini?” | Graf kod |
| Bahasa yang tidak diliputi oleh tatabahasa | search bersama edit |
Berkaitan
Bahagian bertajuk “Berkaitan”- Kepintaran kod — mengapa padanan struktur bukan satu regex dengan beberapa langkah tambahan
- Alat ejen terbina — senarai penuh argumen
- Cari kod dengan graf kod — bahagian simbol dan kesan