- ホーム
- Documentation
- ネイティブ
- Natives テキスト/検索パイプライン
Natives テキスト/検索パイプライン
このドキュメントでは、@f5-sales-demo/pi-natives のテキスト/検索サーフェス(grep、glob、text、highlight)について、TypeScript ラッパーから Rust N-API エクスポート、そして JS 結果オブジェクトへのマッピングを説明します。
用語は docs/natives-architecture.md に従います:
- Wrapper:
packages/natives/src/*内の TS API - Rust モジュールレイヤー:
crates/pi-natives/src/*内の N-API エクスポート - 共有スキャンキャッシュ: ディスカバリー/検索フローで使用される
fs_cacheベースのディレクトリエントリキャッシュ
実装ファイル
Section titled “実装ファイル”packages/natives/src/grep/index.tspackages/natives/src/grep/types.tspackages/natives/src/glob/index.tspackages/natives/src/glob/types.tspackages/natives/src/text/index.tspackages/natives/src/text/types.tspackages/natives/src/highlight/index.tspackages/natives/src/highlight/types.tscrates/pi-natives/src/grep.rscrates/pi-natives/src/glob.rscrates/pi-natives/src/glob_util.rscrates/pi-natives/src/fs_cache.rscrates/pi-natives/src/text.rscrates/pi-natives/src/highlight.rscrates/pi-natives/src/fd.rs
JS API ↔ Rust エクスポートマッピング
Section titled “JS API ↔ Rust エクスポートマッピング”| JS ラッパー API | Rust エクスポート (#[napi], snake_case -> camelCase) | Rust モジュール |
|---|---|---|
grep(options, onMatch?) | grep | grep.rs |
searchContent(content, options) | search | grep.rs |
hasMatch(content, pattern, options?) | hasMatch | grep.rs |
fuzzyFind(options) | fuzzyFind | fd.rs |
glob(options, onMatch?) | glob | glob.rs |
invalidateFsScanCache(path?) | invalidateFsScanCache | fs_cache.rs |
wrapTextWithAnsi(text, width) | wrapTextWithAnsi | text.rs |
truncateToWidth(text, maxWidth, ellipsis, pad) | truncateToWidth | text.rs |
sliceWithWidth(line, startCol, length, strict?) | sliceWithWidth | text.rs |
extractSegments(line, beforeEnd, afterStart, afterLen, strictAfter) | extractSegments | text.rs |
sanitizeText(text) | sanitizeText | text.rs |
visibleWidth(text) | visibleWidth | text.rs |
highlightCode(code, lang, colors) | highlightCode | highlight.rs |
supportsLanguage(lang) | supportsLanguage | highlight.rs |
getSupportedLanguages() | getSupportedLanguages | highlight.rs |
サブシステム別パイプライン概要
Section titled “サブシステム別パイプライン概要”1) 正規表現検索 (grep、searchContent、hasMatch)
Section titled “1) 正規表現検索 (grep、searchContent、hasMatch)”入力/オプションフロー
Section titled “入力/オプションフロー”- TS ラッパーがオプションをネイティブに転送します:
grep/index.tsはoptionsをほぼそのまま渡し、コールバックを(match) => voidから napi スレッドセーフコールバック形式(err, match)にラップします。searchContentとhasMatchは文字列/Uint8Arrayを直接渡します。
grep.rs内の Rust オプション構造体がキャメルケースフィールド(ignoreCase、maxCount、contextBefore、contextAfter、maxColumns、timeoutMs)をデシリアライズします。grepはtimeoutMs+AbortSignalからCancelTokenを作成し、task::blocking("grep", ...)内で実行します。
実行ブランチ
Section titled “実行ブランチ”- インメモリブランチ(純粋ユーティリティ)
search→search_sync→ 提供されたコンテンツバイトに対してrun_searchを実行。- ファイルシステムスキャンなし、
fs_cacheなし。
- 単一ファイルブランチ(ファイルシステム依存)
grep_syncがパスを解決し、メタデータがファイルであることを確認し、ripgrep マッチャーを通じてファイルごとに最大MAX_FILE_BYTES(4 MiB)までストリームします。
- ディレクトリブランチ(ファイルシステム依存)
cache: trueの場合、fs_cache::get_or_scanによるオプションのキャッシュルックアップ。cache: falseの場合、fs_cache::force_rescanによる新規スキャン。- キャッシュ経過時間が
empty_recheck_ms()を超えた場合のオプションの空結果再チェック。 - エントリフィルタリング:ファイルのみ + オプションの glob フィルター(
glob_util)+ オプションの型フィルターマッピング(js、ts、rustなど)。
検索/収集セマンティクス
Section titled “検索/収集セマンティクス”- 正規表現エンジン:
ignoreCaseとmultilineを持つgrep_regex::RegexMatcherBuilder。 - コンテキスト解決:
contextBefore/contextAfterがレガシーのcontextをオーバーライド。- 非コンテンツモードではコンテキスト収集をゼロに設定。
- 出力モード:
content=> ヒットごとに1つのGrepMatch。countとfilesWithMatchesはともにカウントスタイルのエントリにマップ(lineNumber=0、line=""、matchCountが設定)。
- 制限:
- グローバルな
offsetとmaxCountがファイル全体にわたって適用。 maxCountが未設定でoffset == 0の場合のみ並列パスが使用され、それ以外では決定的なグローバルオフセット/リミットセマンティクスを維持するために順次パスが使用されます。
- グローバルな
JS への結果整形
Section titled “JS への結果整形”- Rust の
SearchResult/GrepResultフィールドは N-API オブジェクトフィールド変換を通じて TS 型にマップされます。 - カウンターは N-API を越える前に
u32にクランプされます。 - オプションのブール値は一部のパスで true の場合のみ含まれます(
limitReached)。 - ストリーミングコールバックは整形された各
GrepMatch(コンテンツまたはカウントエントリ)を受け取ります。
失敗時の動作
Section titled “失敗時の動作”searchContentは正規表現/検索の失敗に対してスローする代わりにSearchResult.errorを返します。grepはハードエラー(無効なパス、無効な glob/正規表現、キャンセルタイムアウト/アボート)で reject します。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 スキャンを共有しますが、マッチングロジックは異なります。
glob フロー
Section titled “glob フロー”- TS ラッパー(
glob/index.ts):path.resolve(options.path)。- デフォルト値:
pattern="*"、hidden=false、gitignore=true、recursive=true。
- Rust の
globがGlobConfigを構築し、glob_util::compile_globを通じてパターンをコンパイル。 - エントリソース:
cache=true=>get_or_scan+ オプションの stale-emptyforce_rescan。cache=false=>force_rescan(..., store=false)(新規のみ)。
- フィルタリング:
.gitは常にスキップ。- リクエストされない限り
node_modulesをスキップ(includeNodeModulesまたは node_modules を含むパターン)。 - glob マッチを適用。
- ファイルタイプフィルターを適用;シンボリックリンクの
file/dirフィルターはターゲットメタデータを解決。
maxResultsで切り捨てる前に、mtime 降順によるオプションのソート(sortByMtime)。
fuzzyFind フロー(fd.rs に実装)
Section titled “fuzzyFind フロー(fd.rs に実装)”- TS ラッパーは
grepモジュールからエクスポートされますが、Rust の実装はfd.rsにあります。 fs_cacheからの共有スキャンソースで、同じキャッシュ/非キャッシュ分岐と stale-empty 再チェックポリシー。- スコアリング:
- 完全一致 / 前方一致 / 部分一致 / サブシーケンスベースのファジースコア
- セパレーター/句読点で正規化されたスコアリングパス
- ディレクトリボーナスと決定的なタイブレーク(
score desc、次にpath asc)
- シンボリックリンクエントリはファジー結果から除外されます。
失敗時の動作
Section titled “失敗時の動作”- 無効な 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_hiddenuse_gitignore
キャッシュ状態遷移
Section titled “キャッシュ状態遷移”- ミス / 無効
- TTL が
0またはキーが存在しない/期限切れ -> 新規collect_entries。
- TTL が
- ヒット
- エントリ経過時間が
cache_ttl_ms()未満 -> キャッシュされたエントリ +cache_age_msを返す。
- エントリ経過時間が
- Stale-empty 再チェック(
glob/grep/fdでの呼び出し側ポリシー)- クエリがゼロマッチで
cache_age_ms >= empty_recheck_ms()の場合、1回の再スキャンを強制。
- クエリがゼロマッチで
- 無効化
invalidateFsScanCache(path?):- 引数なし:すべてのキーをクリア
- パス引数:ルートがそのターゲットパスのプレフィックスであるキーを削除
Stale 結果のトレードオフ
Section titled “Stale 結果のトレードオフ”- キャッシュは即座の一貫性よりも低レイテンシの繰り返しスキャンを優先します。
- TTL ウィンドウは stale な正/偽の結果を返す可能性があります。
- 空結果の再チェックは、追加の1回のスキャンコストで古いキャッシュスキャンの stale な偽陰性を削減します。
- 明示的な無効化は、ファイル変更後の正確性フックとして意図されています。
4) ANSI テキストユーティリティ (text)
Section titled “4) ANSI テキストユーティリティ (text)”これらは純粋なインメモリユーティリティです(ファイルシステムスキャンなし)。
text.rsがターミナルセルセマンティクスを担当:- ANSI シーケンスの解析
- 書記素対応の幅とスライシング
- ラップ/切り捨て/サニタイズ動作
grep.rsの行切り捨て(maxColumns)は別:- マッチした行の
...を伴う単純な文字境界切り捨て - ANSI 状態を維持せず、ターミナルセル幅を考慮しない
- マッチした行の
wrapTextWithAnsi:可視幅で折り返し、アクティブな SGR コードを折り返された行に引き継ぎます。truncateToWidth:省略記号ポリシー(Unicode、Ascii、Omit)、オプションの右パディング、変更がない場合に元の JS 文字列を返すファストパスを持つ可視セル切り捨て。sliceWithWidth:オプションの厳密な幅制約を持つ列スライシング。extractSegments:オーバーレイの前後のセグメントを抽出し、afterセグメントの ANSI 状態を復元します。sanitizeText:ANSI エスケープ + 制御文字を除去し、孤立サロゲートを削除し、\rを除去して CR/LF を正規化します。visibleWidth:可視ターミナルセルをカウントします(タブは Rust 実装の固定TAB_WIDTHを使用)。
失敗時の動作
Section titled “失敗時の動作”テキスト関数は一般的に決定的な変換された出力を返します。エラーは JS 文字列変換境界(N-API 引数変換の失敗)に限定されます。
5) シンタックスハイライト (highlight)
Section titled “5) シンタックスハイライト (highlight)”highlight.rs は純粋な変換です(FS なし、キャッシュなし)。
- ラッパーが
code、オプションのlang、および ANSI カラーパレットを転送。 - Rust が以下の方法でシンタックスを解決:
- トークン/名前ルックアップ
- 拡張子ルックアップ
- エイリアステーブルフォールバック(
ts/tsx/js -> JavaScriptなど) - 未解決時はプレーンテキストシンタックスにフォールバック
- syntect の
ParseStateとスコープスタックで各行を解析。 - スコープを 11 のセマンティックカラーカテゴリにマップし、ANSI カラーコードを注入/リセット。
失敗時の動作
Section titled “失敗時の動作”- 行ごとの解析失敗は呼び出しを失敗させません:その行はハイライトされずに追加され、処理は続行します。
- 不明/サポートされていない言語はプレーンテキストシンタックスにフォールバックします。
純粋ユーティリティ vs ファイルシステム依存フロー
Section titled “純粋ユーティリティ vs ファイルシステム依存フロー”| フロー | ファイルシステムアクセス | 共有キャッシュ | 備考 |
|---|---|---|---|
searchContent / hasMatch | なし | なし | 提供されたバイト/文字列に対する正規表現のみ |
text モジュール関数 | なし | なし | ANSI/幅/サニタイズのみ |
highlight モジュール関数 | なし | なし | シンタックス + ANSI カラーリングのみ |
glob | あり | オプション | ディレクトリスキャン + glob フィルタリング |
fuzzyFind | あり | オプション | ディレクトリスキャン + ファジースコアリング |
grep(ファイル/ディレクトリパス) | あり | オプション(ディレクトリモード) | ファイルに対する ripgrep、オプションのフィルター/コールバック |
エンドツーエンドライフサイクルサマリー
Section titled “エンドツーエンドライフサイクルサマリー”- 呼び出し元が型付きオプションで TS ラッパーを呼び出す。
- ラッパーがデフォルト値(特に
glob)を正規化し、native.*エクスポートに転送。 - Rust がオプションを検証/正規化し、マッチャー/検索設定を構築。
- ファイルシステムフローでは、エントリがスキャンされ(キャッシュヒット/ミス/再スキャン)、フィルタリング/スコアリングされる。
- ワーカーループが定期的にキャンセルハートビートを呼び出し、タイムアウト/アボートで実行を終了可能。
- Rust が出力を N-API オブジェクト(
lineNumber、matchCount、limitReachedなど)に整形。 - TS ラッパーが型付き JS オブジェクト(および
grep/glob用のオプションのマッチごとのコールバック)を返す。