# 機能設計書 65-モジュール名でファイル検索

## 概要

本ドキュメントは、serve-dにおけるモジュール名でのファイル検索機能（served/findFilesByModule）の設計を記述する。D言語のモジュール名からプロジェクトと依存関係内の対応するファイルを検索して返却する。

### 本機能の処理概要

**業務上の目的・背景**：D言語ではモジュール名（例: `std.stdio`）とファイルパスが対応関係にある。開発中にモジュール名からそのソースファイルの実体パスを取得する必要がある場面がある。本機能はモジュール名を入力として、対応するファイルの絶対パスを返却する。標準ライブラリのモジュールに対してはキャッシュを活用し高速に結果を返す。

**機能の利用シーン**：
- エディタからモジュール名を指定してソースファイルを開きたい場合
- インポート文のモジュール名から実際のファイルパスを特定したい場合
- 依存関係内のモジュールの実体を確認したい場合

**主要な処理内容**：
1. モジュール名が空の場合はnullを返却する
2. キャッシュに一致するモジュール名がある場合は即座に返却する
3. 全ワークスペースインスタンスのインポートファイルとインポートパスを収集する
4. 各ファイルからModulemanComponentでモジュール名を抽出し照合する
5. 標準ライブラリ（stdで始まるモジュール）はキャッシュに保存する
6. インポートパス配下のファイルも走査し、パスからモジュール名を推定する

**関連システム・外部連携**：ファイルシステムへの直接アクセス。workspace-dのModulemanComponentでモジュール名を解析。

**権限による制御**：特別な権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 62 | モジュール検索（served/findFilesByModule） | 主画面 | モジュール名からプロジェクトと依存関係内の対応するファイルを検索する |

## 機能種別

データ検索・取得

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| module_ | string | Yes | 検索するD言語モジュール名（例: std.stdio） | 空文字列の場合nullを返却 |

### 入力データソース

LSPクライアントからの `served/findFilesByModule` メソッド呼び出し。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | string[] | 一致したファイルの絶対パスの配列。一致なしの場合null |

### 出力先

LSPクライアントへのレスポンス（JSON-RPC応答）。

## 処理フロー

### 処理シーケンス

```
1. served/findFilesByModuleリクエストを受信
   └─ findFilesByModule(module_)関数が呼び出される
2. 空文字列チェック
   └─ module_が空の場合はnullを返却
3. キャッシュチェック
   └─ modFileCacheに一致があれば即座に返却
4. インポートファイルとインポートパスの収集
   └─ 標準ライブラリパスをimportPathsに追加
   └─ 全インスタンスからimportFilesとimportPathsを収集
5. インポートファイル一覧からの検索
   └─ 各ファイルからModulemanComponentでモジュール名を抽出
   └─ stdで始まるモジュールはキャッシュに追加
   └─ モジュール名が一致するファイルを結果に追加
6. インポートパス配下のファイル走査
   └─ 各ディレクトリ配下のファイルをbreadth走査
   └─ moduleNameForFile()でモジュール名を推定
   └─ stdで始まるモジュールはキャッシュに追加
   └─ モジュール名が一致するファイルを結果に追加
7. 結果返却
```

### フローチャート

```mermaid
flowchart TD
    A[served/findFilesByModule リクエスト受信] --> B{module_ は空?}
    B -->|Yes| C[null を返却]
    B -->|No| D{キャッシュにヒット?}
    D -->|Yes| E[キャッシュ結果を返却]
    D -->|No| F[stdlibPath + 全インスタンスの importFiles/importPaths を収集]
    F --> G[importFiles からモジュール名抽出・照合]
    G --> H[importPaths 配下からモジュール名推定・照合]
    H --> I[結果配列を返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-65-01 | モジュール名照合 | ModulemanComponentまたはパスからモジュール名を抽出し、入力と完全一致するファイルを返す | 常時 |
| BR-65-02 | 標準ライブラリキャッシュ | stdで始まるモジュール名のファイルパスをmodFileCacheにキャッシュする | モジュール名がstdで始まる場合 |
| BR-65-03 | 処理済みファイルスキップ | cachedModuleFilesで既に処理済みのファイルはスキップする | 常時 |
| BR-65-04 | パスからのモジュール名推定 | ModulemanComponentで取得できない場合、ディレクトリパスとファイル名からモジュール名を推定する | moduleNameForFile内 |

### 計算ロジック

moduleNameForFileのモジュール名推定:
```
file = buildNormalizedPath(file)
dir = buildNormalizedPath(dir)
if file.startsWith(dir):
    return file[dir.length..].stripExtension.translate("/" -> ".", "\\" -> ".")
else:
    return baseName(file).stripExtension
```

## データベース操作仕様

### 操作別データベース影響一覧

データベース操作はない。ファイルシステムのみ走査。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル読み取りエラー | ファイルの読み取りに失敗した場合 | 該当ファイルをスキップ |

### リトライ仕様

なし。キャッシュにより同一モジュールの再検索は高速化される。

## トランザクション仕様

トランザクション管理は不要。読み取り専用操作。

## パフォーマンス要件

- 標準ライブラリのモジュールはキャッシュ（modFileCache）により高速にアクセス可能
- cachedModuleFilesにより処理済みファイルのスキップで重複処理を回避
- ファイルの読み取りバッファ（8KB）を使用してメモリ効率を向上

## セキュリティ考慮事項

ファイルシステムの読み取りアクセスのみ。

## 備考

- `@protocolMethod("served/findFilesByModule")` アノテーションにより登録
- modFileCache（string[string]型）とcachedModuleFiles（string[]型）はモジュールレベルのグローバルキャッシュ
- readCodeWithBufferでバッファを使ったファイル読み取りを行う
- binarySearchでcachedModuleFilesの高速検索を実施

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | file_search.d | `source/served/commands/file_search.d` | cachedModuleFiles（74行目）とmodFileCache（75行目）のキャッシュ構造 |

**読解のコツ**: `cachedModuleFiles` は処理済みファイルパスのソート済み配列で、`binarySearch` で高速検索される。`modFileCache` はモジュール名からファイルパスへのマッピング。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | file_search.d | `source/served/commands/file_search.d` | findFilesByModule関数（76-140行目） |

**主要処理フロー**:
1. **79-80行目**: 空文字列チェック
2. **82-83行目**: キャッシュチェック（modFileCache）
3. **85-87行目**: 8KBバッファの確保とスコープ終了時の破棄
4. **89-100行目**: importFiles/importPathsの収集
5. **102-118行目**: importFilesからのモジュール名抽出とマッチング
6. **119-137行目**: importPaths配下のファイル走査とモジュール名推定

#### Step 3: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | file_search.d | `source/served/commands/file_search.d` | moduleNameForFile関数（142-154行目） |

**主要処理フロー**:
- **143-147行目**: ModulemanComponentでモジュール名抽出を試行
- **148-151行目**: ファイルパスとディレクトリの正規化、パスからモジュール名推定
- **152-153行目**: フォールバック：ファイル名のみからモジュール名推定

### プログラム呼び出し階層図

```
findFilesByModule(module_) [file_search.d:76-140]
    |
    +-- modFileCache (キャッシュチェック)
    |
    +-- selectedWorkspace.stdlibPath() (標準ライブラリパス取得)
    |
    +-- backend.instances (全ワークスペースインスタンスの列挙)
    |   +-- instance.importFiles
    |   +-- instance.importPaths
    |
    +-- backend.get!ModulemanComponent.moduleName() (モジュール名抽出)
    |
    +-- moduleNameForFile() [file_search.d:142-154]
    |   +-- ModulemanComponent.moduleName() (第一手段)
    |   +-- パスからの推定 (フォールバック)
    |
    +-- cachedModuleFiles.binarySearch() (処理済みチェック)
    +-- cachedModuleFiles.insertSorted() (キャッシュ追加)
```

### データフロー図

```
[入力]                         [処理]                              [出力]

served/findFilesByModule ──▶  findFilesByModule(module_)     ──▶  string[] (マッチしたファイルパス)
(module_: string)              |
                              +-- modFileCache (キャッシュ)
                              +-- 標準ライブラリパス
                              +-- 全インスタンスのimportFiles
                              +-- 全インスタンスのimportPaths
                              +-- ModulemanComponent (モジュール名解析)
                              +-- ファイルシステム走査
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| file_search.d | `source/served/commands/file_search.d` | ソース | findFilesByModule関数の定義（76-154行目） |
| extension.d | `source/served/extension.d` | ソース | バックエンドインスタンス管理 |
| types.d | `source/served/types.d` | ソース | ワークスペース設定 |
| filereader.d | `lsp/source/served/lsp/filereader.d` | ソース | readCodeWithBuffer関数 |
