
# PHP API

## `Greph\Greph`

فئة `Greph\Greph` هي نقطة الدخول الثابتة. وتتيح جميع عمليات البحث وإعادة الكتابة والفهرسة. تقبل كل الطرق مسارًا واحدًا أو قائمة مسارات.

```php
use Greph\Greph;
```

### `walk`

```php
public static function walk(string|array $paths, ?WalkOptions $options = null): FileList
```

حلّ `$paths` إلى `FileList` مسطّح من مسارات الملفات المطلقة. يراعي gitignore و`.grephignore` ومرشحات أنواع الملفات وأنماط glob وتضمين الملفات المخفية وتتبع الروابط الرمزية واكتشاف الملفات الثنائية والحد الأقصى لحجم الملف.

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

$files = Greph::walk('src', new WalkOptions(
    fileTypeFilter: new FileTypeFilter(['php']),
));

foreach ($files->paths() as $path) {
    echo "$path\n";
}
```

---

### `searchText`

```php
public static function searchText(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
): array
```

نفّذ بحثًا نصيًا وأعِد `list<TextFileResult>`. ويعرض كل `TextFileResult` مسار الملف وقائمة من كائنات `TextMatch` (السطر والعمود والمحتوى والالتقاطات والسياق الاختياري).

```php
use Greph\Greph;
use Greph\Text\TextSearchOptions;

$results = Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(
        fixedString: true,
        caseInsensitive: true,
        beforeContext: 1,
        afterContext: 1,
        jobs: 4,
    ),
);

foreach ($results as $file) {
    foreach ($file->matches as $match) {
        echo "{$file->file}:{$match->line}:{$match->content}\n";
    }
}
```

عند تفعيل `jobs > 1` وتجاوز عدد الملفات حدّ العمال، يوزّع `searchText` عملية الفحص تلقائيًا على `WorkerPool`. وإلا فتُنفذ داخل العملية.

---

### `searchAst`

```php
public static function searchAst(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
): array
```

نفّذ بحثًا بنيويًا في AST وأعِد `list<AstMatch>`. تُكتب الأنماط بصياغة المصدر PHP مع متغيرات وصفية من `$VAR` و`$$$VARIADIC`. ويتضمن كل `AstMatch` الملف و`PhpParser\Node` الملتقط والالتقاطات وإزاحات بايتات وسطور البداية والنهاية ومقطع المصدر المطابق.

```php
use Greph\Greph;
use Greph\Ast\AstSearchOptions;

$matches = Greph::searchAst(
    'new $CLASS()',
    'src',
    new AstSearchOptions(),
);

foreach ($matches as $match) {
    echo "{$match->file}:{$match->startLine}:{$match->code}\n";
}
```

---

### `rewriteAst`

```php
public static function rewriteAst(
    string $searchPattern,
    string $rewritePattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
): array
```

نفّذ إعادة كتابة بنيوية وأعِد `list<RewriteResult>`. ويعرض كل `RewriteResult` مسار الملف والمحتوى الأصلي والمحتوى بعد إعادة الكتابة وعدد الاستبدالات. وتحافظ عمليات إعادة الكتابة على التنسيق: إذ لا تُدرج إلا نطاقات العقد المطابقة، ويظل باقي الملف دون تغيير.

```php
$rewrites = Greph::rewriteAst(
    'array($$$ITEMS)',
    '[$$$ITEMS]',
    'src',
);

foreach ($rewrites as $result) {
    if ($result->changed()) {
        file_put_contents($result->file, $result->rewrittenContents);
    }
}
```

لا تكتب الواجهة إلى القرص؛ فالمتصل هو من يقرر تطبيق التغييرات. ويطبقها CLI ما لم يتم ضبط `--dry-run` أو `--interactive`.

---

### البحث النصي المفهرس

#### `buildTextIndex`

```php
public static function buildTextIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): IndexBuildResult
```

أنشئ فهرسًا جديدًا لثلاثيات الأحرف ومنشورات المعرّفات الخاصة بـ `$rootPath`. يُخزّن الفهرس في `$indexPath` (والافتراضي هو `$rootPath/.greph-index`). يمكن أن تكون `$lifecycle` هي `static` أو `manual-refresh` أو `opportunistic-refresh` أو `strict-stale-check`. ويُعاد `IndexBuildResult` يتضمن عدد الملفات وثلاثيات الأحرف وأعداد العناصر المضافة والمحدّثة والمحذوفة والتي لم تتغير.

#### `refreshTextIndex`

```php
public static function refreshTextIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): IndexBuildResult
```

حدّث فهرس نص موجودًا تدريجيًا. تُعاد تجزئة الملفات، ولا تُعاد كتابة سوى الإدخالات التي تغيرت.

#### `searchTextIndexed`

```php
public static function searchTextIndexed(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

نفّذ بحثًا نصيًا باستخدام الفهرس المُحمّل. يُصدر خطأ وقت التشغيل إذا لم يكن الفهرس موجودًا (استدعِ `buildTextIndex` أولًا). ويُعاد `list<TextFileResult>` بالبنية نفسها تمامًا التي في `searchText`.

```php
Greph::buildTextIndex('.');
$results = Greph::searchTextIndexed('function', 'src');
```

#### `searchTextIndexedMany`

```php
public static function searchTextIndexedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?TextSearchOptions $options = null,
): array
```

نفّذ بحثًا نصيًا باستخدام الفهارس المُحمّلة عبر عدة مجلدات لفهارس النص. يبحث Greph في كل فهرس مناسب، ويزيل التكرار استنادًا إلى مسار الملف المطلق، ولا يعود إلى الفحص الأصلي إلا للمسارات الواقعة خارج جميع جذور الفهارس المقدمة.

#### `loadIndexSet`

```php
public static function loadIndexSet(?string $manifestPath = null): IndexSet
```

حمّل بيان مجموعة الفهارس، وافتراضيًا `.greph-index-set.json` في مجلد العمل الحالي.

#### `searchTextIndexedSet`

```php
public static function searchTextIndexedSet(
    string $pattern,
    string|array $paths,
    ?TextSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

حلّ إدخالات `text` المحددة من بيان مجموعة الفهارس، ونفّذ ما يعادل `searchTextIndexedMany`.

---

### بحث AST المفهرس

#### `buildAstIndex` / `refreshAstIndex`

```php
public static function buildAstIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstIndexBuildResult
public static function refreshAstIndex(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstIndexBuildResult
```

أنشئ فهرس حقائق AST أو حدّثه تدريجيًا. تُخزّن الحقائق المستخرجة افتراضيًا في `$rootPath/.greph-ast-index`.

#### `searchAstIndexed`

```php
public static function searchAstIndexed(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

استخدم فهرس الحقائق لتضييق نطاق العناصر المرشحة قبل إعادة التحقق من المطابقات في المصدر. ويُعاد بالهيئة نفسها `list<AstMatch>` التي في `searchAst`.

#### `searchAstIndexedMany`

```php
public static function searchAstIndexedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?AstSearchOptions $options = null,
): array
```

نفّذ بحثًا عن حقائق AST باستخدام الفهارس المُحمّلة عبر عدة مجلدات لفهارس AST.

#### `searchAstIndexedSet`

```php
public static function searchAstIndexedSet(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

حلّ إدخالات `ast-index` المحددة من بيان مجموعة الفهارس، ونفّذ ما يعادل `searchAstIndexedMany`.

#### `buildAstCache` / `refreshAstCache`

```php
public static function buildAstCache(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstCacheBuildResult
public static function refreshAstCache(
    string $rootPath = '.',
    ?string $indexPath = null,
    IndexLifecycle|IndexLifecycleProfile|string|null $lifecycle = null,
): AstCacheBuildResult
```

أنشئ مخزن أشجار التحليل المخزّنة مؤقتًا أو حدّثه تدريجيًا. تُخزّن الأشجار المتسلسلة افتراضيًا في `$rootPath/.greph-ast-cache`.

#### `searchAstCached`

```php
public static function searchAstCached(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $indexPath = null,
): array
```

نفّذ بحث AST باستخدام أشجار التحليل المخزّنة مؤقتًا، مع تخطي المحلل تمامًا. ويُعاد بالهيئة نفسها `list<AstMatch>` التي في `searchAst`.

#### `searchAstCachedMany`

```php
public static function searchAstCachedMany(
    string $pattern,
    string|array $paths,
    array $indexPaths,
    ?AstSearchOptions $options = null,
): array
```

نفّذ بحث AST المُحمّل عبر عدة مجلدات للتخزين المؤقت.

#### `searchAstCachedSet`

```php
public static function searchAstCachedSet(
    string $pattern,
    string|array $paths,
    ?AstSearchOptions $options = null,
    ?string $manifestPath = null,
    array $entryNames = [],
): array
```

حلّ إدخالات `ast-cache` المحددة من بيان مجموعة الفهارس، ونفّذ ما يعادل `searchAstCachedMany`.

---

## `Greph\Text\TextSearchOptions`

كائن خيارات للبحث النصي للقراءة فقط.

```php
new TextSearchOptions(
    bool $fixedString = false,
    bool $caseInsensitive = false,
    bool $wholeWord = false,
    bool $invertMatch = false,
    ?int $maxCount = null,
    int $beforeContext = 0,
    int $afterContext = 0,
    bool $countOnly = false,
    bool $filesWithMatches = false,
    bool $filesWithoutMatches = false,
    bool $jsonOutput = false,
    bool $tracePlan = false,
    int $jobs = 1,
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = true,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
    bool $showLineNumbers = true,
    bool $showFileNames = true,
)
```

التحقق:

- `jobs >= 1`
- `beforeContext, afterContext >= 0`
- `maxCount === null || maxCount >= 1`

استخدم `walkOptions()` لاشتقاق `WalkOptions` المطابق إذا أردت اجتياز شجرة الملفات على نحو منفصل.

يستخدم الباحثون المفهرسون المُحمّلون `tracePlan`، كما تستخدمه تدفقات `greph-index` CLI لإصدار تشخيصات المخطط إلى `stderr`. أما `searchText` الأصلي فلا يستخدمه.

---

## `Greph\Ast\AstSearchOptions`

كائن خيارات للبحث وإعادة الكتابة في AST للقراءة فقط.

```php
new AstSearchOptions(
    string $language = 'php',
    int $jobs = 1,
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = true,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
    bool $skipParseErrors = true,
    bool $dryRun = false,
    bool $interactive = false,
    bool $jsonOutput = false,
    bool $tracePlan = false,
)
```

مرشح أنواع الملفات الافتراضي لنمط AST هو `php`. عندما تكون `skipParseErrors` هي `true` (الافتراضي)، تُتخطى الملفات التي يتعذر تحليلها بصمت؛ غيّرها إلى `false` لإظهار أخطاء التحليل كاستثناءات. يستخدم الباحثون المُحمّلون في AST `tracePlan`، كما تستخدمه `greph-index ast-index|ast-cache search` لإصدار تشخيصات تقليص العناصر المرشحة.

---

## `Greph\Walker\WalkOptions`

كائن خيارات متجوّل الملفات للقراءة فقط.

```php
new WalkOptions(
    bool $respectIgnore = true,
    bool $includeHidden = false,
    bool $followSymlinks = false,
    bool $skipBinaryFiles = false,
    bool $includeGitDirectory = false,
    ?FileTypeFilter $fileTypeFilter = null,
    int $maxFileSizeBytes = 10485760,
    array $globPatterns = [],
)
```

---

## `Greph\Walker\FileTypeFilter`

حلّ أنواع الملفات المسماة إلى قوائم امتدادات. الأسماء المستعارة المضمنة:

| الاسم المستعار | الامتدادات |
|---|---|
| `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` |

```php
new FileTypeFilter(includeTypes: ['php'], excludeTypes: ['md']);
```

---

## كائنات النتائج

### `Greph\Text\TextFileResult`

```php
final readonly class TextFileResult
{
    public string $file;
    /** @var list<TextMatch> */
    public array $matches;

    public function matchCount(): int;
    public function hasMatches(): bool;
}
```

### `Greph\Text\TextMatch`

```php
final readonly class TextMatch
{
    public string $file;
    public int $line;
    public int $column;
    public string $content;
    public string $matchedText;
    /** @var array<int|string, string> */
    public array $captures;
    /** @var list<array{line: int, content: string}> */
    public array $beforeContext;
    /** @var list<array{line: int, content: string}> */
    public array $afterContext;
}
```

### `Greph\Ast\AstMatch`

```php
final readonly class AstMatch
{
    public string $file;
    public PhpParser\Node $node;
    /** @var array<string, mixed> */
    public array $captures;
    public int $startLine;
    public int $endLine;
    public int $startFilePos;
    public int $endFilePos;
    public string $code;
}
```

### `Greph\Ast\RewriteResult`

```php
final readonly class RewriteResult
{
    public string $file;
    public string $originalContents;
    public string $rewrittenContents;
    public int $replacementCount;

    public function changed(): bool;
}
```

### `Greph\Index\IndexBuildResult`

```php
final readonly class IndexBuildResult
{
    public string $rootPath;
    public string $indexPath;
    public int $fileCount;
    public int $trigramCount;
    public int $addedFiles;
    public int $updatedFiles;
    public int $deletedFiles;
    public int $unchangedFiles;
}
```

يتبع `AstIndexBuildResult` و`AstCacheBuildResult` البنية نفسها مع استبدال `factCount` و`cachedTreeCount` بهما على الترتيب.

---

## الاستثناءات

يطلق Greph ثلاثة استثناءات محددة النوع، جميعها في `Greph\Exceptions`:

| الاستثناء | متى يحدث |
|---|---|
| `WalkerException` | أخطاء نظام الملفات أثناء التنقل (مسار مفقود أو دليل غير قابل للقراءة) |
| `PatternException` | تعبير نمطي أو نمط AST غير صالح |
| `ParseException` | تعذر تحليل المصدر PHP (فقط عندما يكون `skipParseErrors: false`) |

تطلق أساليب البحث المفهرس `\RuntimeException` عند عدم وجود فهرس في الموقع المطلوب. يتيح `greph-index` CLI الخيار `--fallback scan` لالتقاط هذه الاستثناءات والرجوع إلى فحص غير مفهرس.
