
# Індексований пошук AST

Індексований пошук AST — це версія [пошуку AST](https://greph.inline0.dev/uk/docs/modes/ast) із прогрітим кешем. Під час першого виклику факти на рівні вузлів (назви викликів, створення екземплярів, оголошення класів і методів) витягуються у сховище на диску; наступні виклики використовують його, щоб пропускати файли, які очевидно не містять структурного збігу. Потім засіб зіставлення повторно перевіряє кандидатів за вихідним кодом.

Індекс фактів доступний через підкоманду `greph-index ast-index` CLI та методи фасаду `Greph::buildAstIndex()` / `Greph::searchAstIndexed()`. Він також використовується у прогрітих сценаріях пошуку в кількох індексах і наборах на основі маніфесту.

## Створення індексу

```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
```

За замовчуванням індекс фактів зберігається в `<root>/.greph-ast-index/`.

Після успішного створення виводиться однорядковий підсумок:

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

Чотири лічильники показують кількість доданих, оновлених, видалених і незмінених файлів від часу останнього створення індексу.

## Оновлення індексу

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

`refresh` повторно обходить індексований кореневий каталог, повторно аналізує змінені файли та перезаписує лише змінені рядки фактів. У виводі використовуються ті самі чотири лічильники, що й для текстового індексу.

Профілі життєвого циклу працюють так само, як і для прогрітих текстових індексів:

- `static`: ніколи автоматично не перевіряє актуальність і не вносить змін
- `manual-refresh`: повідомляє про застарілий стан у `stats`, але не оновлює індекс під час пошуку
- `opportunistic-refresh`: оновлює індекс під час пошуку, лише якщо набір змін достатньо малий
- `strict-stale-check`: відхиляє пошук із застарілим індексом замість його оновлення

## Запити до індексу

```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
```

Синтаксис метазмінних такий самий, як у нативному пошуку AST. Повний опис граматики дивіться в [Режими / Пошук AST](https://greph.inline0.dev/uk/docs/modes/ast).

### Параметри

| Прапорець | Значення |
|---|---|
| `--lang NAME` | Мова AST. За замовчуванням: `php` |
| `-j N`, `--jobs N` | Кількість паралельних робочих процесів |
| `-l`, `--files-with-matches` | Показувати лише файли, що відповідають умовам |
| `--glob GLOB` | Включати лише файли, шляхи до яких відповідають GLOB |
| `--type NAME` / `--type-not NAME` | Фільтр за типом файлу |
| `--json` | Виводити дані у форматі JSON |
| `--no-ignore` | Ігнорувати `.gitignore` і `.grephignore` |
| `--hidden` | Включати приховані файли |
| `--strict-parse` | Завершувати роботу з помилкою аналізу замість пропуску таких файлів |
| `--fallback MODE` | Поведінка за відсутності індексу: `fail` (за замовчуванням) або `scan` |
| `--index-dir DIR` | Використовувати нестандартний каталог індексу |
| `--trace-plan` | Виводити діагностику планувальника прогрітого AST у `stderr` |
| `--show-index-origin` | Додавати на початку виводу назву відповідного індексу в режимі кількох індексів або наборів |

### Резервний режим за відсутності індексу

За замовчуванням `ast-index search` видає помилку, якщо в запитаному розташуванні немає індексу. Передайте `--fallback scan`, щоб перейти до нативного сканування AST. Цей параметр підійде інструментам, яким потрібен індексований пошук за його наявності, але які мають видавати результати й до створення індексу.

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

### Пошук у кількох індексах

Щоб шукати однією командою в кількох прогрітих індексах AST, можна повторювати `--index-dir`. Це зручно для структур, як-от WordPress ядра з плагіном або темою.

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

Якщо ввімкнено `--show-index-origin`, перед результатом виводиться назва відповідного запису прогрітого індексу, щоб було видно, з якого кореневого каталогу отримано збіг.

### Набори індексів на основі маніфесту

Для стабільних прогрітих конфігурацій створіть маніфест, щоб `greph-index set` працював із групами індексів:

```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()' .
```

Підкоманди наборів використовують ті самі параметри життєвого циклу, перевірки застарілого стану та діагностики планувальника, що й пряме використання `ast-index`.

### Діагностика планувальника

`--trace-plan` показує, як Greph звузив запит перед запуском повного засобу зіставлення. Для `ast-index` це зазвичай охоплює:

- грубий підпис фактів, витягнутий із шаблону
- кількість прогрітих індексів, у яких виконувався пошук
- кількість файлів, відсіяних фільтром фактів
- кількість файлів-кандидатів, повторно проаналізованих для точної структурної перевірки

## Що зберігає індекс

Для кожного індексованого файлу засіб витягування фактів AST створює рядок для кожного «цікавого» вузла. Набір типів фактів охоплює конструкції, які найчастіше шукають за шаблонами AST:

- Виклики функцій і методів (за назвою викликаної функції чи методу)
- Створення екземплярів класів (за назвою класу)
- Оголошення класів, інтерфейсів, трейтів і переліків (за назвою)
- Оголошення функцій (за назвою)
- Оголошення методів (за назвою та видимістю)
- Інструкції використання

Коли надходить запит, `Greph\Ast\AstFactQuery` перетворює шаблон пошуку на грубий підпис фактів (наприклад, «має містити `new` будь-якого класу») і відбирає відповідні записи зі сховища фактів. Файли, що залишилися після відбору, повторно аналізуються та зіставляються з повним шаблоном.

Отже, індекс фактів слугує *попереднім фільтром*, а не сховищем повних збігів. Під час зіставлення вихідний код усе одно аналізується, тому структурна точність така сама, як у нативному пошуку AST; зменшується лише набір файлів-кандидатів.

## Коли використовувати

Режим індексованого AST стане у пригоді, якщо:

- Ви багаторазово виконуєте ті самі структурні запити до однієї кодової бази.
- Шаблони мають розпізнавані ознаки (назву виклику, назву класу або тип оголошення), які зберігає засіб витягування фактів.
- Вам потрібна менша затримка, ніж під час повторного аналізу кожного файлу.

Для шаблонів, характерна ознака яких відсутня в наборі фактів (наприклад, складних вкладених виразів без розпізнаваного початкового елемента), зазвичай краще підходить [режим кешованого AST](https://greph.inline0.dev/uk/docs/indexed/cache): він повністю пропускає етап аналізу, не покладаючись на грубий підпис.

## Програмне використання

```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` приймає те саме `AstSearchOptions`, що й нативний пошук AST, і повертає той самий формат `list<AstMatch>`. Для роботи з кількома індексами або потоками на основі маніфесту використовуйте `searchAstIndexedMany(...)` і `searchAstIndexedSet(...)`.
