To narzędzie pozwala dokonywać magicznych zmian w kodzie—bez AI
W krainie programowania tekst jest królem, więc narzędzia takie jak grep, sed i awk są fantastycznymi towarzyszami twojego kompilatora lub interpretera. Skrzynka narzędziowa każdego programisty może również skorzystać z systemu kontroli wersji opartego na tekście, takiego jak Git.
Ale te wszystkie narzędzia działają na ogólnym poziomie tekstu. Chociaż wyrażenia regularne mogą być niesamowicie potężne, wciąż nie są idealnie dopasowane do gramatyki języka programowania. Do znaczącego, semantycznego wyszukiwania potrzebujesz innego rodzaju narzędzia. Oto ast-grep.
Czym jest ast-grep i dlaczego miałbyś go potrzebować?
Supermocne wyszukiwanie, które rozumie Twój kod
Załóżmy, że chcesz listę wszystkich nazw funkcji w swoim kodzie. Pierwsza próba mogłaby wyglądać mniej więcej tak:
grep -r 'function' ...
A potem możesz zdać sobie sprawę, że dopasowujesz zbyt wiele nieistotnych wystąpień, więc udoskonalasz swoje wyrażenie regularne:
egrep -r '^function\W' ...
Kontynuujesz w ten sposób, aż w końcu zdajesz sobie sprawę, że, niezależnie od tego, co robisz, twoje wyszukiwanie dopasuje coś w rodzaju:
/*
The following should be:
function foo(a, b, c)
but that’s not going to work because...
*/
Narzędzia takie jak grep po prostu nie rozumieją kontekstu czegoś, co wygląda jak deklaracja funkcji wewnątrz komentarza. Działają tylko poprzez dopasowywanie poszczególnych znaków, a nie poprzez uwzględnianie szerszego znaczenia, które mogą obejmować kombinacje tych znaków.
ast-grep jest inny. Zamiast czytać tekst znak po znaku, linia po linii, analizuje tekst (tak jak kompilator) i buduje abstrakcyjne drzewo składniowe (AST), które reprezentuje rzeczywiste znaczenie twojego kodu. Używając tego, może następnie przeprowadzać semantyczne wyszukiwania elementów takich jak deklaracje zmiennych, wywołania funkcji i tak dalej.
Pod maską ast-grep używa popularnej biblioteki Tree-sitter, która pozwala mu wspierać szeroki zakres języków tak różnorodnych jak Python, Java i Go. ast-grep jest napisany w Rust, więc działa wydajnie, nawet przeszukując duże bazy kodu. Jest to ważne, ponieważ, ponieważ musi w pełni przeanalizować pliki przed ich przeszukaniem, jest dużo więcej pracy niż przy standardowym wyszukiwaniu tekstowym.
Jak wyszukiwać prawie wszystko za pomocą ast-grep
Używanie wiersza poleceń lub aplikacji internetowej, która jest idealna dla początkujących
Najprostsze użycie ast-grep polega na użyciu opcji -p do określenia jednego prostego wzorca.
ast-grep -p 'console.log'
Bez żadnych argumentów ścieżki, ast-grep będzie przeszukiwać pliki w bieżącym katalogu, rekurencyjnie. Jeśli nie określisz języka, ast-grep wywnioskuje go na podstawie rozszerzenia pliku. Program pogrupuje wyniki według pliku, drukując szczegóły każdego dopasowania, podkreślając odpowiednie części:
Zauważ, że to wyszukiwanie zwraca wywołania funkcji bez argumentów oraz odniesienie do właściwości metody, która nawet nie jest wywołaniem. Jednakże szuka konkretnie obiektu o nazwie console, więc nie znajdzie następującego:
with (console) {
log("Hello, world.");
}
Ale poprawnie zignoruje "'console.log'" jako ciąg znaków i "/* console.log */" jako komentarz. W tym momencie radzę Ci zbadać playground ast-grep, aplikację webową, która uruchamia ast-grep w tle i prezentuje jego wyniki:
Jak widać, playground wyraźnie pokazuje dokładnie, co pasuje, a co nie. Jest to w przeciwieństwie do programu wiersza poleceń, który filtruje dane wejściowe i zwraca tylko dopasowania. Uważam, że playground był bardzo przydatny, gdy po raz pierwszy uczyłem się o ast-grep i próbowałem tworzyć własne wzorce.
Możesz używać zmiennych meta do dopasowywania bardziej dynamicznych treści. Zmienna meta zaczyna się od $ i używa tylko wielkich liter, a także podkreśleń i cyfr. Aby znaleźć wszystkie wywołania console.log z jednym argumentem, użyj tego wzorca:
console.log($SINGLE_ARG)
Zauważ, że wzorzec pasuje do wywołań z jednym argumentem, a nie do tych bez argumentów lub z większą ich liczbą:
Jeśli chcesz dopasować wiele argumentów, możesz użyć zmiennej meta wielokrotnej, która zaczyna się od trzech znaków dolara:
console.log($$$MULTIPLE_ARGS)
Ten wzorzec dopasuje wszystkie wywołania console.log, w tym te z zerową lub wieloma argumentami:
Dla bardziej zaawansowanych wyszukiwań, ast-grep obsługuje składnię reguł w formacie YAML. Możesz jej użyć do definiowania bardzo kontekstowych wyszukiwań, w pełni wykorzystując strukturę AST.
Na przykład, oto reguła, która dopasowuje wszystkie wywołania console.log, console.debug i console.warn, oraz wywołania console.error, jeśli nie znajdują się one wewnątrz bloku catch:
id: no-console-except-error
language: typescript
rule:
any:
- pattern: console.error($$$)
not:
inside:
kind: catch_clause
stopBy: end
- pattern: console.$METHOD($$$)
constraints:
METHOD:
regex: 'log|debug|warn'
Zmień swój kod bez ręcznej edycji
Dzięki starannemu przygotowaniu i testowaniu, ast-grep może być potężnym zautomatyzowanym edytorem
ast-grep to już potężne narzędzie, ale wykracza poza samo wyszukiwanie. Dzięki funkcji zamiany, ast-grep pozwala również na modyfikowanie kodu. Oznacza to, że można dokonać niezwykle czasochłonnych zmian w kilka sekund, zarówno automatycznie, jak i w trybie interaktywnym.
Rozważ poprzedni przykład console.log. Wyobraź sobie jedną ze swoich baz kodu, która jest pełna kodu debugującego wywołującego console.log. Postanawiasz, że chcesz czegoś nieco bardziej zaawansowanego, więc zaczynasz od własnej funkcji, my_logger:
function my_logger() {
if (GLOBAL_DEBUG) {
console.log.apply(null, arguments)
}
}
To tylko prosty wrapper dla console.log, z globalną flagą, na razie. Ale chodzi o to, że będziesz musiał zamienić każde wywołanie console.log() na wywołanie my_logger. Używając ast-grep, jest to prosty proces. Zacznij od pliku z regułami, np. fix-logging.yml:
rule:
pattern: console.log($$$MULTIPLE_ARGS)
fix: my_logger($$$MULTIPLE_ARGS)
Następnie uruchom ją w ten sposób, aby zobaczyć zmiany, które zostałyby wprowadzone:
ast-grep scan --rule fix-logging.yml
Jeśli jesteś zadowolony z wyników, możesz użyć ast-grep, aby wprowadził te zmiany za Ciebie, aktualizując pliki na miejscu za pomocą opcji --update-all:
ast-grep scan --rule fix-logging.yml --update-all
Istnieje kilka trybów, których można używać do wprowadzania zmian, w tym tryb interaktywny, który prawdopodobnie jest najbezpieczniejszym sposobem uruchamiania ast-grep, gdy zaznajamiasz się z nim.
Pomimo stromej krzywej uczenia się, opanowanie ast-grep przyniesie nagrodę
Nie ma co do tego wątpliwości: ast-grep to skomplikowany program. Przykłady, które tu zamieściłem, są po łatwiejszej stronie skali, a jeśli zagłębisz się w dokumentację, zobaczysz, że to narzędzie ma do zaoferowania o wiele więcej.
Chociaż może to być przytłaczające, plac zabaw bardzo pomaga, a korzystanie z trybu interaktywnego do oczyszczania swojej bazy kodu jest świetnym sposobem na rozpoczęcie nauki ast-grep.









