Tovább a tartalomhoz

Kód strukturális refaktorálása

Ez az útmutató megmutatja, hogyan vegyen rá egy ügynököt egy széles körű, mechanikus változtatásra — egy codemod, egy tömeges API-migráció vagy egy minta, amelyet el akar tüntetni — strukturális kereséssel és átírással, úgy, hogy a változás a kiírás előtt átnézésre előkészítve várjon.

Az ast_grep alak szerint illeszti a kódot. Az ast_edit átírja. A resolve véglegesíti vagy elveti.

A strukturális eszközök azokat a nyelveket fedik le, amelyeket a kódgráf feldolgoz: Dart, JavaScript, TypeScript, TSX, PHP, Python, Rust, Zig, C, C++, Go, Java, Ruby, C#, Swift, Kotlin, R, Assembly, MATLAB és Ada. Szükségük van az előkészített tree-sitter nyelvtanokra, amelyek egy kiszállított buildben mindig rendelkezésre állnak — egy hiányzó nyelvtan leállítja a szervert, nem pedig lerontja a keresést.

Soha ne írjon át olyasmit, amit nem nézett meg. Kérje meg az ügynököt a keresésre:

Keresse meg az összes helyet, ahol egy nullable értéken dispose()-t hívunk, amelyet épp most ellenőriztünk nullára.

ast_grep(pattern: "if ($X != null) $X.dispose()", language: "dart")

A kimenet file:line, valamint minden helyhez az illeszkedő forrás.

Token Illeszkedés
$NAME Bármely egyetlen csomópont, elkapva
$$$NAME Testvérek bármely sorozata — argumentumok, utasítások
$_ Bármi, név nélkül elkapva

Amelyik igazán számít: egy ismételt $NAME-nek ugyanazt a szöveget kell elkapnia.

if ($X != null) $X.dispose()

olyan őrfeltételre illeszkedik, amely azt szabadítja fel, amit vizsgált. Nem illeszkedik viszont az if (a != null) b.dispose() esetre — ami általában pont az a hiba, amelyet keresett. Ezt egyetlen szöveges keresés sem tudja kifejezni.

Két dolgot érdemes kipróbálni, ebben a sorrendben:

  1. Kisebbítse. foo($X) az if (a) { foo($X); } előtt. Egy minta, amely önmagában nem érvényes kód, gyakran nem az a szerkezet, amelyet valójában keresett.
  2. Nevezze meg a nyelvet. A language: csak akkor következtethető ki, ha a path egyetlen fájlra mutat.

Az olyan mintát, amelyet egyetlen feldolgozási környezet sem fogad el, feldolgozhatatlanként jelentenek — az eszköz ezt mondja ahelyett, hogy „nincs találat”-ot jelentene valamire, amit soha nem úgy olvastak, ahogy kinéz.

Írjon át, és nézze meg, mielőtt bekerül

Szekció neve “Írjon át, és nézze meg, mielőtt bekerül”
ast_edit(
pattern: "if ($X != null) $X.dispose()",
rewrite: "$X?.dispose()",
language: "dart",
)

Az eredmény egy javaslat:

(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.

Még semmi sincs a lemezen. Olvassa el a listát, ellenőrizzen néhány helyet, amelyet a keresés jelentett, majd:

resolve(edit_id: "edit_1", action: "accept")

vagy

resolve(edit_id: "edit_1", action: "discard")

Ellenőrizze a munkáját a fordítóval

Szekció neve “Ellenőrizze a munkáját a fordítóval”

Azért érdemes strukturálisan eljárni, mert a változás széles hatókörű. Pont a széles körű változások azok, ahol egy hihetőnek tűnő átírás eltöri a típust. A véglegesítés után kérjen diagnosztikát:

lsp(action: "diagnostics", file: "*")

A file: "*" a projekt saját ellenőrzőjét futtatja (dart analyze, tsc --noEmit, cargo check, go build) fájlonkénti lekérdezés helyett — ez a helyes kérdésforma egy negyven fájlt érintő változás után.

Tegyük fel, hogy a log(msg, level) helyébe a log(level: level, message: msg) lép.

ast_grep(pattern: "log($MSG, $LEVEL)", language: "dart")

Nézze meg a találatokat. Ha közülük néhány egy másik kétargumentumos log, szűkítse a mintát úgy, hogy a path értékét arra a könyvtárra korlátozza, amelyik a keresett példányt tartalmazza, ahelyett hogy a különbséget magában a mintában próbálná kifejezni.

ast_edit(
pattern: "log($MSG, $LEVEL)",
rewrite: "log(level: $LEVEL, message: $MSG)",
path: "lib/features/telemetry",
language: "dart",
)

Ezután resolve, majd lsp(action: "diagnostics", file: "*").

Helyzet Jobb eszköz
Szimbólum átnevezése lsp_rename — a hivatkozásokat követi, nem az alakokat
Sztring, megjegyzés vagy fájlnév megkeresése search (tartalom) / search_files (nevek)
„Mi törik el, ha ezt megváltoztatom?” A kódgráf
Olyan nyelv, amelyet a nyelvtanok nem fednek le search plusz edit