
# Обходчик файлов

Каждый режим Greph (текст, AST, переписывание, индексированный текст, индексированный AST, кэшированный 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` возможно только при обходе того же набора файлов, что и у этих инструментов.
