
# Wyszukiwanie AST z indeksem

Wyszukiwanie AST z indeksem to wariant [wyszukiwania AST](https://greph.inline0.dev/pl/docs/modes/ast) z rozgrzaną pamięcią podręczną. Pierwsze wywołanie wyodrębnia fakty na poziomie węzłów (nazwy wywołań, utworzone instancje, deklaracje klas i metod) i zapisuje je na dysku. Kolejne wywołania korzystają z tego magazynu, aby pominąć pliki, które ewidentnie nie zawierają dopasowania strukturalnego. Następnie mechanizm dopasowujący ponownie weryfikuje kandydatów na podstawie kodu źródłowego.

Indeks faktów jest dostępny w podpoleceniu `greph-index ast-index` CLI oraz metodach fasady `Greph::buildAstIndex()` / `Greph::searchAstIndexed()`. Obsługuje też wyszukiwanie obejmujące wiele indeksów z rozgrzaną pamięcią i zestawy oparte na manifeście.

## Tworzenie indeksu

```bash
# Full build at the current directory
./vendor/bin/greph-index ast-index build .

# Full build at an explicit root
./vendor/bin/greph-index ast-index build path/to/repo

# Use a non-default index directory
./vendor/bin/greph-index ast-index build . --index-dir /tmp/greph-ast-index

# Build a mutable overlay that can refresh cheaply on demand
./vendor/bin/greph-index ast-index build . \
  --lifecycle opportunistic-refresh \
  --auto-refresh-max-files 32 \
  --auto-refresh-max-bytes 1048576
```

Domyślnie indeks faktów jest przechowywany w `<root>/.greph-ast-index/`.

Po pomyślnym utworzeniu indeksu wyświetlane jest jednowierszowe podsumowanie:

```text
Built AST index for 2547 files in .greph-ast-index (84931 fact rows, +2547 ~0 -0 =0)
```

Cztery liczniki pokazują liczbę dodanych, zaktualizowanych, usuniętych i niezmienionych plików od czasu ostatniego tworzenia indeksu.

## Odświeżanie indeksu

```bash
./vendor/bin/greph-index ast-index refresh .
```

`refresh` ponownie przegląda indeksowany katalog główny, analizuje zmienione pliki i przepisuje tylko zmienione wiersze faktów. Dane wyjściowe zawierają te same cztery liczniki co indeks tekstowy.

Profile cyklu życia działają tak samo jak w przypadku rozgrzanych indeksów tekstowych:

- `static`: nigdy automatycznie nie sprawdzaj aktualności ani nie modyfikuj
- `manual-refresh`: zgłaszaj nieaktualny stan w `stats`, ale nigdy nie odświeżaj podczas wyszukiwania
- `opportunistic-refresh`: odświeżaj podczas wyszukiwania tylko wtedy, gdy zbiór zmian jest wystarczająco mały
- `strict-stale-check`: odrzucaj nieaktualne wyszukiwania zamiast odświeżać indeks

## Wyszukiwanie w indeksie

```bash
./vendor/bin/greph-index ast-index search 'new $CLASS()' src
./vendor/bin/greph-index ast-index search '$obj->$method($$$ARGS)' src
./vendor/bin/greph-index ast-index search --json 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search -l 'array($$$ITEMS)' src
./vendor/bin/greph-index ast-index search --trace-plan 'new $CLASS()' src
```

Składnia metazmiennych jest identyczna jak w natywnym wyszukiwaniu AST. Pełną gramatykę znajdziesz w sekcji [Tryby / wyszukiwanie AST](https://greph.inline0.dev/pl/docs/modes/ast).

### Opcje

| Flaga | Znaczenie |
|---|---|
| `--lang NAME` | Język AST. Domyślnie: `php` |
| `-j N`, `--jobs N` | Liczba procesów roboczych działających równolegle |
| `-l`, `--files-with-matches` | Wyświetlaj tylko pasujące pliki |
| `--glob GLOB` | Uwzględniaj tylko pliki, których ścieżki pasują do GLOB |
| `--type NAME` / `--type-not NAME` | Filtr typu pliku |
| `--json` | Generuj dane wyjściowe JSON |
| `--no-ignore` | Ignoruj `.gitignore` i `.grephignore` |
| `--hidden` | Uwzględniaj ukryte pliki |
| `--strict-parse` | Zgłaszaj błędy analizy zamiast je pomijać |
| `--fallback MODE` | Zachowanie w przypadku braku indeksu: `fail` (domyślnie) lub `scan` |
| `--index-dir DIR` | Używaj niestandardowego katalogu indeksu |
| `--trace-plan` | Zapisuj diagnostykę planera rozgrzanego AST do `stderr` |
| `--show-index-origin` | Poprzedzaj dane wyjściowe etykietą pasującego indeksu w trybie wielu indeksów lub zestawu |

### Zapasowe wyszukiwanie bez indeksu

Domyślnie `ast-index search` zgłasza błąd, gdy w żądanej lokalizacji nie ma indeksu. Przekaż `--fallback scan`, aby zamiast tego przeprowadzić natywne skanowanie AST. To właściwe ustawienie dla narzędzi, które mają korzystać z wyszukiwania indeksowanego, gdy jest dostępne, ale powinny zwracać wyniki również wtedy, gdy indeks nie został jeszcze utworzony.

```bash
./vendor/bin/greph-index ast-index search --fallback scan 'new $CLASS()' src
```

### Wyszukiwanie w wielu indeksach

Możesz przeszukać kilka rozgrzanych indeksów AST jednym poleceniem, powtarzając `--index-dir`. Przydaje się to w układach takich jak WordPress wraz z wtyczką lub motywem.

```bash
./vendor/bin/greph-index ast-index search \
  --index-dir ../wordpress/.greph-ast-index \
  --index-dir ./.greph-ast-index \
  --show-index-origin \
  'new $CLASS()' .
```

Gdy włączono `--show-index-origin`, przed danymi wyjściowymi pojawia się nazwa pasującej pozycji rozgrzanego indeksu, dzięki czemu widać, który katalog główny zawiera wynik.

### Zestawy indeksów oparte na manifeście

W przypadku stabilnych konfiguracji rozgrzanych indeksów zdefiniuj manifest i pozwól `greph-index set` działać na zgrupowanych indeksach:

```bash
./vendor/bin/greph-index set build
./vendor/bin/greph-index set stats --mode ast-index --dry-refresh
./vendor/bin/greph-index set search --mode ast-index --show-index-origin 'new $CLASS()' .
```

Podpolecenia zestawu obsługują cykl życia, sprawdzanie nieaktualności i diagnostykę planera tak samo jak bezpośrednie użycie `ast-index`.

### Diagnostyka planera

`--trace-plan` pokazuje, jak Greph zawęził zapytanie przed uruchomieniem pełnego mechanizmu dopasowującego. W przypadku `ast-index` obejmuje to zazwyczaj:

- przybliżony podpis faktów wyodrębniony ze wzorca
- liczbę przeszukanych rozgrzanych indeksów
- liczbę plików odrzuconych przez filtr faktów
- liczbę plików kandydujących, które ponownie przeanalizowano w celu dokładnej weryfikacji strukturalnej

## Co przechowuje indeks

Dla każdego indeksowanego pliku moduł wyodrębniania faktów AST zapisuje wiersz dla każdego „interesującego” węzła. Zestaw rodzajów faktów obejmuje konstrukcje, których najczęściej dotyczą wzorce AST:

- Wywołania funkcji i metod (według wywoływanej nazwy)
- Tworzenie instancji klas (według nazwy klasy)
- Deklaracje klas, interfejsów, cech i wyliczeń (według nazwy)
- Deklaracje funkcji (według nazwy)
- Deklaracje metod (według nazwy i widoczności)
- Instrukcje use

Po nadejściu zapytania `Greph\Ast\AstFactQuery` przekształca wzorzec wyszukiwania w przybliżony podpis faktów (na przykład „musi zawierać `new` dowolnej klasy”) i przecina zbiory w magazynie faktów. Pliki, które przejdą to przecięcie, są następnie ponownie analizowane i dopasowywane do pełnego wzorca.

Oznacza to, że indeks faktów jest *filtrem wstępnym*, a nie pełnym magazynem dopasowań. Etap dopasowywania nadal analizuje kod źródłowy, więc poprawność strukturalna jest taka sama jak w natywnym wyszukiwaniu AST; zmniejsza się tylko zbiór kandydatów.

## Kiedy używać

Tryb AST z indeksem sprawdza się, gdy:

- Wielokrotnie wykonujesz te same zapytania strukturalne w tej samej bazie kodu.
- Wzorce dotyczą rozpoznawalnych kształtów (nazwy wywołania, nazwy klasy, rodzaju deklaracji), które zapisuje moduł wyodrębniania faktów.
- Chcesz zmniejszyć opóźnienie w porównaniu z ponowną analizą każdego pliku.

W przypadku wzorców, których cechy wyróżniającej nie ma w zbiorze faktów (na przykład złożonych zagnieżdżonych wyrażeń bez rozpoznawalnego początku), lepiej sprawdza się zwykle tryb [buforowanego AST](https://greph.inline0.dev/pl/docs/indexed/cache), ponieważ całkowicie pomija etap analizy bez polegania na przybliżonym podpisie.

## Użycie programowe

```php
use Greph\Greph;
use Greph\Ast\AstSearchOptions;
use Greph\Index\IndexLifecycleProfile;

Greph::buildAstIndex('.', lifecycle: IndexLifecycleProfile::OpportunisticRefresh);

$matches = Greph::searchAstIndexed(
    'new $CLASS()',
    'src',
    new AstSearchOptions(jobs: 4, tracePlan: true),
);
```

`searchAstIndexed` przyjmuje ten sam `AstSearchOptions` co natywne wyszukiwanie AST i zwraca dane o tym samym kształcie `list<AstMatch>`. W przypadku przepływów obejmujących wiele indeksów lub opartych na manifeście użyj `searchAstIndexedMany(...)` i `searchAstIndexedSet(...)`.
