تخطَّ إلى المحتوى

خط أنابيب النص/البحث الأصلي

تُعيّن هذه الوثيقة السطح النصي/البحثي لـ @f5-sales-demo/pi-natives (grep، وglob، وtext، وhighlight) من أغلفة TypeScript إلى صادرات Rust N-API وعودةً إلى كائنات النتائج في JS.

تتبع المصطلحات ملف docs/natives-architecture.md:

  • الغلاف: واجهة برمجة TS في packages/natives/src/*
  • طبقة وحدة Rust: صادرات N-API في crates/pi-natives/src/*
  • ذاكرة تخزين الفحص المشتركة: ذاكرة تخزين مدخلات المجلدات المدعومة بـ fs_cache والمستخدمة في تدفقات الاكتشاف/البحث
  • packages/natives/src/grep/index.ts
  • packages/natives/src/grep/types.ts
  • packages/natives/src/glob/index.ts
  • packages/natives/src/glob/types.ts
  • packages/natives/src/text/index.ts
  • packages/natives/src/text/types.ts
  • packages/natives/src/highlight/index.ts
  • packages/natives/src/highlight/types.ts
  • crates/pi-natives/src/grep.rs
  • crates/pi-natives/src/glob.rs
  • crates/pi-natives/src/glob_util.rs
  • crates/pi-natives/src/fs_cache.rs
  • crates/pi-natives/src/text.rs
  • crates/pi-natives/src/highlight.rs
  • crates/pi-natives/src/fd.rs

تعيين واجهة برمجة JS ↔ صادرات Rust

Section titled “تعيين واجهة برمجة JS ↔ صادرات Rust”
واجهة برمجة الغلاف JSصادر Rust (#[napi]، snake_case -> camelCase)وحدة Rust
grep(options, onMatch?)grepgrep.rs
searchContent(content, options)searchgrep.rs
hasMatch(content, pattern, options?)hasMatchgrep.rs
fuzzyFind(options)fuzzyFindfd.rs
glob(options, onMatch?)globglob.rs
invalidateFsScanCache(path?)invalidateFsScanCachefs_cache.rs
wrapTextWithAnsi(text, width)wrapTextWithAnsitext.rs
truncateToWidth(text, maxWidth, ellipsis, pad)truncateToWidthtext.rs
sliceWithWidth(line, startCol, length, strict?)sliceWithWidthtext.rs
extractSegments(line, beforeEnd, afterStart, afterLen, strictAfter)extractSegmentstext.rs
sanitizeText(text)sanitizeTexttext.rs
visibleWidth(text)visibleWidthtext.rs
highlightCode(code, lang, colors)highlightCodehighlight.rs
supportsLanguage(lang)supportsLanguagehighlight.rs
getSupportedLanguages()getSupportedLanguageshighlight.rs

نظرة عامة على خط الأنابيب حسب النظام الفرعي

Section titled “نظرة عامة على خط الأنابيب حسب النظام الفرعي”

1) البحث بالتعبيرات النمطية (grep، وsearchContent، وhasMatch)

Section titled “1) البحث بالتعبيرات النمطية (grep، وsearchContent، وhasMatch)”

تدفق المدخلات/الخيارات

Section titled “تدفق المدخلات/الخيارات”
  1. يُمرر الغلاف TS الخيارات إلى الوحدة الأصلية:
    • يُمرر grep/index.ts الخيارات options دون تغيير إلى حد بعيد، ويُغلّف رد النداء من الشكل (match) => void إلى شكل رد نداء napi الآمن في الخيوط (err, match).
    • يُمرر searchContent وhasMatch النص/Uint8Array مباشرةً.
  2. تُفسّر هياكل خيارات Rust في grep.rs حقول camelCase (ignoreCase، وmaxCount، وcontextBefore، وcontextAfter، وmaxColumns، وtimeoutMs).
  3. يُنشئ grep رمز CancelToken من timeoutMs + AbortSignal وينفذ داخل task::blocking("grep", ...).
  • فرع الذاكرة (أداة مساعدة خالصة)
    • searchsearch_syncrun_search على بايتات المحتوى المقدمة.
    • لا فحص لنظام الملفات، ولا fs_cache.
  • فرع الملف الواحد (يعتمد على نظام الملفات)
    • يحل grep_sync المسار، ويتحقق من أن البيانات الوصفية تخص ملفاً، ثم يبث ما يصل إلى MAX_FILE_BYTES لكل ملف (4 MiB) عبر مطابق ripgrep.
  • فرع المجلد (يعتمد على نظام الملفات)
    • البحث الاختياري في ذاكرة التخزين المؤقت عبر fs_cache::get_or_scan عند تعيين cache: true.
    • إجراء فحص جديد عبر fs_cache::force_rescan عند تعيين cache: false.
    • إعادة التحقق الاختيارية من النتائج الفارغة عند تجاوز عمر ذاكرة التخزين المؤقت للقيمة empty_recheck_ms().
    • تصفية المدخلات: ملفات فقط + تصفية glob اختيارية (glob_util) + تصفية النوع الاختيارية (js، ts، rust، إلخ).
  • محرك التعبيرات النمطية: grep_regex::RegexMatcherBuilder مع ignoreCase وmultiline.
  • حل السياق:
    • تتجاوز contextBefore/contextAfter الخيار القديم context.
    • تُصفّر أوضاع غير المحتوى مجموعة السياق.
  • أوضاع الإخراج:
    • content => مدخل GrepMatch واحد لكل تطابق.
    • يُعيّن كل من count وfilesWithMatches إلى مدخلات نمط العدد (lineNumber=0، line=""، يُعيَّن matchCount).
  • الحدود:
    • يُطبَّق الإزاحة العالمية offset وmaxCount عبر الملفات.
    • يُستخدم المسار المتوازي فقط عند عدم تعيين maxCount وكون offset == 0؛ وإلا يُستخدم المسار التسلسلي للحفاظ على دلالات الإزاحة/الحد العالمية الحتمية.

تشكيل النتائج وإعادتها إلى JS

Section titled “تشكيل النتائج وإعادتها إلى JS”
  • تُعيَّن حقول SearchResult/GrepResult في Rust إلى أنواع TS عبر تحويل حقول كائنات N-API.
  • تُقيَّد العدادات إلى u32 قبل عبور N-API.
  • تُحذف القيم المنطقية الاختيارية ما لم تكن صحيحة في بعض المسارات (limitReached).
  • يتلقى رد نداء البث كل مدخل GrepMatch مُشكَّل (محتوى أو مدخل عدد).
  • يُعيد searchContent قيمة SearchResult.error عند فشل التعبير النمطي/البحث عوضاً عن الرمي بخطأ.
  • يرفض grep عند الأخطاء الحادة (مسار غير صالح، glob/تعبير نمطي غير صالح، انقضاء المهلة/الإلغاء).
  • يُعيد hasMatch قيمة Result<bool> ويرمي عند أنماط غير صالحة أو أخطاء فك ترميز UTF-8.
  • تُتخطى أخطاء فتح/بحث الملفات في فحوصات الملفات المتعددة لكل ملف على حدة؛ ويستمر الفحص.

معالجة التعبيرات النمطية المشوهة

Section titled “معالجة التعبيرات النمطية المشوهة”

يُعالج grep.rs الأقواس المعقوصة قبل تصريف التعبير النمطي:

  • تُهرَّب الأقواس المعقوصة الشبيهة بالتكرار غير الصالح ({/} -> \{/\}) عندما لا يمكنها تشكيل {N}، أو {N,}، أو {N,M}.
  • يمنع ذلك مقاطع قوالب الحروف الشائعة (مثل ${platform}) من الفشل كتكرار مشوه.
  • لا تزال بنية التعبير النمطي غير الصالحة المتبقية تُعيد خطأ في التعبير النمطي.

2) اكتشاف الملفات (glob) والبحث الضبابي في المسارات (fuzzyFind)

Section titled “2) اكتشاف الملفات (glob) والبحث الضبابي في المسارات (fuzzyFind)”

يتشارك glob وfuzzyFind فحوصات fs_cache؛ بينما تختلف منطق المطابقة.

  1. الغلاف TS (glob/index.ts):
    • path.resolve(options.path).
    • القيم الافتراضية: pattern="*"، وhidden=false، وgitignore=true، وrecursive=true.
  2. يبني Rust glob الكائن GlobConfig ويصرّف النمط عبر glob_util::compile_glob.
  3. مصدر المدخلات:
    • cache=true => get_or_scan + إعادة فحص اختيارية للنتائج القديمة-الفارغة.
    • cache=false => force_rescan(..., store=false) (جديد فقط).
  4. التصفية:
    • تخطي .git دائماً.
    • تخطي node_modules ما لم يُطلب ذلك (includeNodeModules أو نمط يذكر node_modules).
    • تطبيق مطابقة glob.
    • تطبيق تصفية نوع الملف؛ تحل فلاتر file/dir للروابط الرمزية البيانات الوصفية للهدف.
  5. الترتيب الاختياري حسب وقت التعديل تنازلياً (sortByMtime) قبل الاقتصار على maxResults.

تدفق fuzzyFind (مُنفَّذ في fd.rs)

Section titled “تدفق fuzzyFind (مُنفَّذ في fd.rs)”
  1. يُصدَّر الغلاف TS من وحدة grep، لكن التنفيذ في Rust يقع في fd.rs.
  2. مصدر الفحص المشترك من fs_cache مع نفس منطق تقسيم ذاكرة التخزين المؤقت/بدونها وسياسة إعادة التحقق من الفارغ القديم.
  3. التسجيل:
    • درجة مبنية على: التطابق التام / يبدأ بـ / يحتوي على / التسلسل الضبابي
    • مسار تسجيل مُعيَّر بالفواصل وعلامات الترقيم
    • مكافأة المجلد وكسر التعادل الحتمي (score desc، ثم path asc)
  4. تُستثنى مدخلات الروابط الرمزية من نتائج البحث الضبابي.
  • نمط glob غير صالح => خطأ من glob_util::compile_glob.
  • يجب أن يكون جذر البحث مجلداً موجوداً (resolve_search_path)، وإلا حدث خطأ.
  • تنتشر الإلغاءات/انتهاءات المهل كأخطاء إجهاض عبر فحوصات CancelToken::heartbeat() في الحلقات.

معالجة أنماط glob المشوهة

Section titled “معالجة أنماط glob المشوهة”

glob_util::build_glob_pattern متسامحة:

  • تُعيَّر \ إلى /.
  • تُضاف تلقائياً **/ بادئةً للأنماط التكرارية البسيطة عند تعيين recursive=true.
  • تُغلق تلقائياً مجموعات التناوب {... غير المتوازنة قبل التصريف.

3) دورة حياة الفحص/التخزين المشترك (fs_cache)

Section titled “3) دورة حياة الفحص/التخزين المشترك (fs_cache)”

يخزن fs_cache نتائج الفحص كمدخلات نسبية مُعيَّرة (path، وfileType، وmtime الاختيارية) مُفهرَسة بـ:

  • جذر البحث القانوني
  • include_hidden
  • use_gitignore

انتقالات حالة ذاكرة التخزين المؤقت

Section titled “انتقالات حالة ذاكرة التخزين المؤقت”
  1. إخفاق / معطل
    • مدة الصلاحية 0 أو المفتاح غائب/منتهي الصلاحية -> collect_entries جديدة.
  2. إصابة
    • عمر المدخل < cache_ttl_ms() -> إعادة المدخلات المخزنة + cache_age_ms.
  3. إعادة التحقق من القديم-الفارغ (سياسة الاستدعاء في glob/grep/fd)
    • إذا أسفر الاستعلام عن صفر تطابقات وكان cache_age_ms >= empty_recheck_ms()، فأجرِ إعادة فحص واحدة.
  4. الإبطال
    • invalidateFsScanCache(path?):
      • بدون وسيطة: مسح جميع المفاتيح
      • مع وسيطة مسار: إزالة المفاتيح التي تتضمن جذورها بادئة مسار الهدف

مقايضة النتائج القديمة

Section titled “مقايضة النتائج القديمة”
  • تُفضّل ذاكرة التخزين المؤقت الفحوصات المتكررة المنخفضة الاستجابة على الاتساق الفوري.
  • يمكن أن تُعيد نافذة مدة الصلاحية نتائج إيجابية/سلبية قديمة.
  • تقلل إعادة التحقق من الفارغ من النتائج السلبية القديمة للفحوصات المخزنة الأقدم، بتكلفة فحص إضافي واحد.
  • الإبطال الصريح هو الخطاف المقصود للصحة بعد تعديلات الملفات.

هذه أدوات مساعدة خالصة في الذاكرة (بدون فحص لنظام الملفات).

  • يمتلك text.rs دلالات خلايا الطرفية:
    • تحليل تسلسلات ANSI
    • العرض المدرك للمخططات البيانية والتقطيع
    • سلوك الالتفاف/القطع/التعقيم
  • قطع الأسطر في grep.rs (maxColumns) منفصلة:
    • قطع بسيط لحدود الأحرف للأسطر المطابقة مع ...
    • غير حافظة لحالة ANSI وغير مدركة لعرض خلايا الطرفية
  • wrapTextWithAnsi: يلتف حسب العرض المرئي، ويحمل رموز SGR النشطة عبر الأسطر الملتفة.
  • truncateToWidth: قطع بالخلايا المرئية مع سياسة علامة الحذف (Unicode، وAscii، وOmit)، وحشو أيمن اختياري، ومسار سريع يُعيد سلسلة JS الأصلية عند عدم التغيير.
  • sliceWithWidth: تقطيع الأعمدة مع تطبيق عرض صارم اختياري.
  • extractSegments: يستخرج المقاطع قبل/بعد تراكب مع استعادة حالة ANSI لمقطع after.
  • sanitizeText: يجرد هروبات ANSI + أحرف التحكم، ويتخلص من الوكلاء المنعزلين، ويُعيَّر CR/LF بإزالة \r.
  • visibleWidth: يحسب خلايا الطرفية المرئية (تستخدم علامات التبويب TAB_WIDTH الثابتة من تنفيذ Rust).

تُعيد دوال النص عموماً مخرجات محولة حتمية؛ تقتصر الأخطاء على حدود تحويل سلاسل JS (فشل تحويلات وسيطات N-API).

5) إبراز بنية الشيفرة (highlight)

Section titled “5) إبراز بنية الشيفرة (highlight)”

highlight.rs تحويل خالص (بدون نظام ملفات، بدون ذاكرة تخزين مؤقت).

  1. يُمرر الغلاف code، وlang الاختيارية، ولوحة ألوان ANSI.
  2. يحل Rust البنية بـ:
    • البحث بالرمز/الاسم
    • البحث بالامتداد
    • جدول الأسماء المستعارة الاحتياطي (ts/tsx/js -> JavaScript، إلخ)
    • الرجوع إلى بنية النص العادي عند عدم الحل
  3. تحليل كل سطر بـ ParseState syntect ومكدس النطاق.
  4. تعيين النطاقات إلى 11 فئة لون دلالية وحقن/إعادة تعيين رموز ألوان ANSI.
  • فشل تحليل السطر لا يُفشل الاستدعاء: يُضاف ذلك السطر دون إبراز ويستمر المعالجة.
  • اللغة المجهولة/غير المدعومة تنتقل إلى بنية النص العادي.

تدفقات الأداة المساعدة الخالصة مقابل المعتمدة على نظام الملفات

Section titled “تدفقات الأداة المساعدة الخالصة مقابل المعتمدة على نظام الملفات”
التدفقالوصول إلى نظام الملفاتذاكرة التخزين المشتركةملاحظات
searchContent / hasMatchلالاتعبير نمطي على البايتات/النص المقدم فقط
دوال وحدة textلالامعالجة ANSI/العرض/التعقيم فقط
دوال وحدة highlightلالاالبنية + تلوين ANSI فقط
globنعماختياريةفحوصات المجلدات + تصفية glob
fuzzyFindنعماختياريةفحوصات المجلدات + التسجيل الضبابي
grep (مسار ملف/مجلد)نعماختيارية (وضع المجلد)ripgrep على الملفات، مع فلاتر/رد نداء اختيارية

ملخص دورة الحياة الشاملة

Section titled “ملخص دورة الحياة الشاملة”
  1. يستدعي المُستدعي الغلاف TS مع خيارات مُكتَّبة.
  2. يُعيَّر الغلاف القيم الافتراضية (ولا سيما glob) ويُمررها إلى صادر native.*.
  3. تُتحقق Rust/تُعيَّر الخيارات وتبني المُطابق/تهيئة البحث.
  4. بالنسبة لتدفقات نظام الملفات، تُفحص المدخلات (إصابة/إخفاق/إعادة فحص في ذاكرة التخزين المؤقت) ثم تُصفى/تُسجَّل.
  5. تستدعي حلقات العمال دورياً نبضة قلب الإلغاء؛ يمكن أن تُنهي انتهاءات المهل/الإلغاءات التنفيذ.
  6. تُشكّل Rust المخرجات إلى كائنات N-API (lineNumber، وmatchCount، وlimitReached، إلخ).
  7. يُعيد الغلاف TS كائنات JS مُكتَّبة (وردود نداء اختيارية لكل تطابق لـ grep/glob).