
# Geïndexeerd AST-zoeken

Geïndexeerd AST-zoeken is de versie van [AST-zoeken](https://greph.inline0.dev/nl/docs/modes/ast) met een opgewarmde cache. Bij de eerste aanroep worden feiten op knooppuntniveau (aanroepnamen, instanties, klassendeclaraties en methodedeclaraties) geëxtraheerd en opgeslagen op schijf. Bij volgende aanroepen gebruikt de opslag deze feiten om bestanden over te slaan die duidelijk geen structurele match kunnen bevatten. Vervolgens controleert de matcher de kandidaten opnieuw aan de hand van de broncode.

De feitenindex is beschikbaar via de subopdracht `greph-index ast-index` CLI en de facademethoden `Greph::buildAstIndex()` / `Greph::searchAstIndexed()`. De index wordt ook gebruikt bij zoekworkflows met meerdere opgewarmde indexen en met sets op basis van manifesten.

## De index bouwen

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

De feitenindex wordt standaard opgeslagen op `<root>/.greph-ast-index/`.

Na een geslaagde build wordt een samenvatting van één regel weergegeven:

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

De vier tellers geven het aantal toegevoegde, bijgewerkte, verwijderde en ongewijzigde bestanden sinds de vorige build weer.

## De index vernieuwen

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

`refresh` doorloopt de geïndexeerde root opnieuw, parseert gewijzigde bestanden opnieuw en herschrijft alleen de feitenrijen die zijn veranderd. De uitvoer gebruikt dezelfde vier tellers als de tekstindex.

Levenscyclusprofielen werken hetzelfde als bij opgewarmde tekstindexen:

- `static`: controleert nooit automatisch of de index actueel is en wijzigt deze nooit automatisch
- `manual-refresh`: meldt een verouderde status in `stats`, maar vernieuwt de index nooit tijdens het zoeken
- `opportunistic-refresh`: vernieuwt de index tijdens het zoeken alleen als de gewijzigde set klein genoeg is
- `strict-stale-check`: weigert verouderde zoekopdrachten in plaats van de index te vernieuwen

## De index doorzoeken

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

De syntaxis voor metavariabelen is identiek aan die van native AST-zoekopdrachten. Zie [Modi / AST Search](https://greph.inline0.dev/nl/docs/modes/ast) voor de volledige grammatica.

### Opties

| Optie | Betekenis |
|---|---|
| `--lang NAME` | AST-taal. Standaard: `php` |
| `-j N`, `--jobs N` | Aantal parallelle workers |
| `-l`, `--files-with-matches` | Alleen overeenkomende bestanden weergeven |
| `--glob GLOB` | Alleen bestanden opnemen waarvan het pad overeenkomt met GLOB |
| `--type NAME` / `--type-not NAME` | Filter op bestandstype |
| `--json` | JSON-uitvoer genereren |
| `--no-ignore` | `.gitignore` en `.grephignore` negeren |
| `--hidden` | Verborgen bestanden opnemen |
| `--strict-parse` | Mislukken bij parsefouten in plaats van deze over te slaan |
| `--fallback MODE` | Gedrag bij ontbrekende index: `fail` (standaard) of `scan` |
| `--index-dir DIR` | Een niet-standaard indexmap gebruiken |
| `--trace-plan` | Diagnostiek van de planner voor opgewarmde AST weergeven in `stderr` |
| `--show-index-origin` | Uitvoer in modus met meerdere indexen of sets vooraf laten gaan door het overeenkomende indexlabel |

### Terugvaloptie bij ontbrekende index

Standaard geeft `ast-index search` een foutmelding als er op de gevraagde locatie geen index bestaat. Geef `--fallback scan` door om in plaats daarvan terug te vallen op een native AST-scan. Dit is de juiste instelling voor tools die geïndexeerd zoeken willen gebruiken wanneer dat beschikbaar is, maar ook resultaten moeten geven als de index nog niet is opgebouwd.

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

### Zoeken in meerdere indexen

Je kunt met één opdracht in meerdere opgewarmde AST-indexen zoeken door `--index-dir` meerdere keren op te geven. Dit is handig voor indelingen zoals WordPress-core met daarnaast een plugin of thema.

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

Wanneer `--show-index-origin` is ingeschakeld, wordt de uitvoer voorafgegaan door de naam van de overeenkomende opgewarmde indexvermelding, zodat je kunt zien welke root de treffer heeft opgeleverd.

### Indexsets op basis van manifesten

Definieer voor stabiele opgewarmde configuraties een manifest en laat `greph-index set` de gegroepeerde indexen doorzoeken:

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

De set-subopdrachten hanteren dezelfde levenscyclusafhandeling, verouderingscontroles en plannerd diagnostiek als rechtstreeks gebruik van `ast-index`.

### Plannerd diagnostiek

`--trace-plan` laat zien hoe Greph de query heeft beperkt voordat de volledige matcher werd uitgevoerd. Voor `ast-index` omvat dit doorgaans:

- de grove feitenhandtekening die uit het patroon is gehaald
- het aantal doorzochte opgewarmde indexen
- het aantal bestanden dat door het feitenfilter is afgewezen
- het aantal kandidaatbestanden dat opnieuw is geparseerd voor exacte structurele verificatie

## Wat de index opslaat

Voor elk geïndexeerd bestand registreert de AST-feitenextractor één rij per 'interessant' knooppunt. De soorten feiten omvatten de constructies waarop AST-patronen zich het vaakst richten:

- Functie- en methodeaanroepen (op basis van de aangeroepen naam)
- Klasse-instanties (op basis van de klassenaam)
- Declaraties van klassen, interfaces, traits en enums (op basis van de naam)
- Functiedeclaraties (op basis van de naam)
- Methodedeclaraties (op basis van de naam en zichtbaarheid)
- Use-statements

Wanneer er een query binnenkomt, vertaalt `Greph\Ast\AstFactQuery` het zoekpatroon naar een grove feitenhandtekening (bijvoorbeeld: 'moet een `new` van een willekeurige klasse bevatten') en doorsnijdt die met de feitenopslag. De overgebleven bestanden worden opnieuw geparseerd en aan het volledige patroon getoetst.

Dit betekent dat de feitenindex een *prefilter* is, geen volledige matchopslag. Tijdens het matchen wordt de broncode nog steeds geparseerd. De structurele nauwkeurigheid is dus identiek aan die van native AST-zoekopdrachten; alleen de kandidaatset is kleiner.

## Wanneer gebruik je deze?

De geïndexeerde AST-modus is geschikt wanneer:

- Je dezelfde structurele zoekopdrachten herhaaldelijk uitvoert op dezelfde codebase.
- De patronen herkenbare vormen hebben (aanroepnaam, klassenaam, soort declaratie) die door de feitenextractor worden opgeslagen.
- Je minder vertraging wilt dan bij het opnieuw parsen van elk bestand.

Voor patronen waarvan het onderscheidende kenmerk niet in de feitenset staat (bijvoorbeeld complexe geneste expressies zonder herkenbare kop) is de [gecachte AST-modus](https://greph.inline0.dev/nl/docs/indexed/cache) meestal geschikter. Deze slaat de parseerstap volledig over zonder op een grove handtekening te vertrouwen.

## Programmatisch gebruik

```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` accepteert dezelfde `AstSearchOptions` als native AST-zoekopdrachten en retourneert hetzelfde `list<AstMatch>`-formaat. Gebruik voor workflows met meerdere indexen of op manifesten gebaseerde sets `searchAstIndexedMany(...)` en `searchAstIndexedSet(...)`.
