
# Обхождач на файлове

Всеки режим 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` или се интегрира безпроблемно с пула от работници. Еднократната реализация на обхождача и споделянето му между режимите означава също, че всеки режим прилага точно едни и същи правила за филтриране, което е от ключово значение за стратегията за тестване с еталон: сравнение с `grep`, `ripgrep` и `ast-grep` е възможно само ако се обхожда същият набор от файлове като при тези инструменти.
