
# Recorredor de archivos

Cada modo de Greph (texto, AST, reescritura, texto indexado, AST indexado, AST en caché, envoltorio `rg`, envoltorio `sg`) comienza recorriendo el árbol de archivos y generando un `Greph\Walker\FileList`. El recorrido es compartido, por lo que las mismas opciones y comportamientos se aplican en todas partes.

## Comportamiento predeterminado

De forma predeterminada, el recorredor:

- Recorre recursivamente todos los directorios dentro de las rutas solicitadas.
- Respeta las reglas de `.gitignore` y `.grephignore` en todos los niveles, incluidas las anulaciones y negaciones anidadas.
- Omite el directorio `.git`.
- Omite los archivos y directorios ocultos (cualquier elemento cuyo nombre empiece por `.`).
- Omite los archivos binarios (detectados por bytes nulos en los primeros 512 bytes del archivo).
- Omite los archivos de más de 10 MiB.
- No sigue enlaces simbólicos.

## Opciones de anulación

| Opción | Efecto |
|---|---|
| `--no-ignore` | Dejar de respetar `.gitignore` y `.grephignore` |
| `--hidden` | Incluir archivos y directorios ocultos |
| `--type NAME` | Incluir solo archivos que coincidan con el alias de tipo indicado |
| `--type-not NAME` | Excluir los archivos que coincidan con el alias de tipo indicado |
| `--glob GLOB` | Incluir solo archivos cuyas rutas coincidan con GLOB. Se puede repetir. |

Las mismas opciones se exponen mediante `Greph\Walker\WalkOptions` para su uso programático.

```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'],
));
```

## Alias de tipos de archivo

Greph incluye un pequeño conjunto de tipos de archivo con nombre. Cada alias corresponde a una lista de extensiones:

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

La lista completa está en `Greph\Walker\FileTypeFilter::TYPE_MAP`.

## Semántica de .gitignore

Greph implementa la coincidencia con gitignore en PHP puro. La semántica coincide con la de `git check-ignore`:

- Los patrones se evalúan en relación con el directorio en el que se encuentran.
- Los archivos `.gitignore` anidados anulan las reglas del directorio superior.
- La negación (`!pattern`) vuelve a incluir una ruta excluida anteriormente.
- El `/` final limita un patrón a los directorios.
- El `/` inicial ancla un patrón al directorio de `.gitignore`.
- `**` coincide con cualquier número de segmentos de ruta.

`.grephignore` utiliza la misma sintaxis y se superpone a `.gitignore`. Es el lugar adecuado para exclusiones específicas de herramientas que no quiera incluir en el control de versiones.

La implementación está en `Greph\Walker\GitignoreFilter`.

## Detección de binarios

El recorredor comprueba si hay bytes nulos en los primeros 512 bytes de cada archivo. Si encuentra alguno, trata el archivo como binario y lo omite. Esto detecta el caso habitual en que un repositorio contiene imágenes, archivos comprimidos o artefactos compilados dentro de un directorio indexado.

Para buscar también en archivos binarios, establezca `skipBinaryFiles: false` en el objeto `Options` correspondiente. Actualmente, CLI no ofrece una opción para ello; use la fachada.

## Enlaces simbólicos

De forma predeterminada, no se siguen los enlaces simbólicos. Establezca `followSymlinks: true` (o pase `-L` / `--follow` al envoltorio `rg`) para seguirlos. El recorredor registra los directorios visitados para evitar que los bucles de enlaces simbólicos causen una recursión infinita.

## Tamaño máximo de archivo

Se omiten los archivos de más de `maxFileSizeBytes` (10 MiB de forma predeterminada). Esto evita que un archivo de registro de 1 GB se cargue accidentalmente en memoria durante un análisis. Cambie el límite en el objeto `Options` cuando necesite cubrir archivos de mayor tamaño.

## Por qué usar un recorredor propio

Greph podría depender de `glob()` o `RecursiveDirectoryIterator`, pero ninguno implementa la semántica de gitignore, ninguno entiende `.grephignore` y ninguno se integra bien con el grupo de trabajadores. Escribir el recorredor una sola vez y compartirlo entre los modos también garantiza que todos apliquen exactamente las mismas reglas de filtrado, algo fundamental para la estrategia de pruebas guiada por un oráculo: la única forma de comparar con `grep`, `ripgrep` y `ast-grep` es recorrer el mismo conjunto de archivos que recorren esas herramientas.
