
# Обхід файлової системи

Кожен режим Greph (text, AST, rewrite, indexed text, indexed AST, cached AST, обгортка `rg`, обгортка `sg`) починається з обходу дерева файлів і створення `Greph\Walker\FileList`. Засіб обходу спільний, тому ті самі прапорці та правила діють усюди.

## Типова поведінка

За замовчуванням засіб обходу:

- Рекурсивно обходить усі каталоги всередині вказаних шляхів.
- На кожному рівні дотримується правил `.gitignore` і `.grephignore`, зокрема вкладених перевизначень і заперечень.
- Пропускає каталог `.git`.
- Пропускає приховані файли й каталоги (усі, назви яких починаються з `.`).
- Пропускає бінарні файли (визначає їх за нульовими байтами в перших 512 байтах файлу).
- Пропускає файли розміром понад 10 MiB.
- Не переходить за символічними посиланнями.

## Прапорці перевизначення

| Прапорець | Дія |
|---|---|
| `--no-ignore` | Не дотримуватися правил `.gitignore` і `.grephignore` |
| `--hidden` | Додавати приховані файли й каталоги |
| `--type NAME` | Додавати лише файли, що відповідають названому псевдоніму типу |
| `--type-not NAME` | Виключати файли, що відповідають названому псевдоніму типу |
| `--glob GLOB` | Додавати лише файли, шляхи яких відповідають GLOB. Можна вказувати кілька разів. |

Ті самі параметри доступні для програмного використання через `Greph\Walker\WalkOptions`.

```php
use Greph\Greph;
use Greph\Walker\FileTypeFilter;
use Greph\Walker\WalkOptions;

$files = Greph::walk('src', new WalkOptions(
    respectIgnore: false,
    includeHidden: true,
    fileTypeFilter: new FileTypeFilter(['php']),
    globPatterns: ['src/**/*.php'],
));
```

## Псевдоніми типів файлів

Greph містить невеликий набір іменованих типів файлів. Кожен псевдонім відповідає списку розширень:

| Псевдонім | Розширення |
|---|---|
| `css` | `css`, `sass`, `scss` |
| `html` | `htm`, `html`, `phtml` |
| `js` | `cjs`, `js`, `mjs` |
| `json` | `json` |
| `md` | `markdown`, `md` |
| `php` | `inc`, `php`, `php3`, `php4`, `php5`, `php7`, `php8`, `phpt`, `phtml` |
| `txt` | `txt` |
| `ts` | `ts`, `tsx` |
| `xml` | `xml` |
| `yaml` | `yaml`, `yml` |

Повний список наведено в `Greph\Walker\FileTypeFilter::TYPE_MAP`.

## Семантика .gitignore

Greph реалізує зіставлення за правилами gitignore лише засобами PHP. Семантика узгоджена з `git check-ignore`:

- Шаблони застосовуються відносно каталогу, у якому вони містяться.
- Вкладені файли `.gitignore` перевизначають правила батьківських каталогів.
- Заперечення (`!pattern`) знову включає шлях, який раніше було виключено.
- Кінцевий `/` обмежує шаблон каталогами.
- Початковий `/` прив'язує шаблон до каталогу файлу `.gitignore`.
- `**` відповідає будь-якій кількості сегментів шляху.

`.grephignore` використовує той самий синтаксис і працює поверх `.gitignore`. Тут зручно задавати специфічні для інструмента винятки, які не потрібно зберігати в системі контролю версій.

Реалізація міститься в `Greph\Walker\GitignoreFilter`.

## Виявлення бінарних файлів

Засіб обходу перевіряє перші 512 байтів кожного файлу на наявність нульових байтів. Якщо їх виявлено, файл вважається бінарним і пропускається. Це дає змогу виявляти поширений випадок, коли в репозиторії в індексованому каталозі є зображення, архіви або скомпільовані артефакти.

Щоб шукати в бінарних файлах, установіть `skipBinaryFiles: false` у відповідному об'єкті `Options`. CLI наразі не надає прапорця для цього; скористайтеся фасадом.

## Символічні посилання

За замовчуванням символічні посилання не обходяться. Установіть `followSymlinks: true` (або передайте `-L` / `--follow` обгортці `rg`), щоб переходити за ними. Засіб обходу відстежує відвідані каталоги, тому цикли символічних посилань не спричиняють нескінченної рекурсії.

## Максимальний розмір файлу

Файли розміром понад `maxFileSizeBytes` (за замовчуванням 10 MiB) пропускаються. Це захищає сканування від випадкового завантаження в пам'ять журналу розміром 1 GB. Якщо потрібно обробляти більші файли, змініть обмеження в об'єкті `Options`.

## Навіщо потрібен власний засіб обходу

Greph міг би використовувати `glob()` або `RecursiveDirectoryIterator`, але жоден із них не реалізує семантику gitignore, не розуміє `.grephignore` і не інтегрується належним чином із пулом воркерів. Одноразова реалізація засобу обходу, спільна для всіх режимів, також гарантує однакові правила фільтрації в кожному режимі. Це критично для стратегії тестування з oracle: порівнювати з `grep`, `ripgrep` і `ast-grep` можна, лише обходячи той самий набір файлів, що й ці інструменти.
