# 機能設計書 71-requireパス解決

## 概要

本ドキュメントは、Lua Language Serverにおけるrequireパス解決機能の設計を記述する。この機能は、Luaの`require`文で指定されたモジュール名から実際のファイルパスを解決し、定義へのジャンプやコード補完を可能にする中核機能である。

### 本機能の処理概要

**業務上の目的・背景**：Luaプロジェクトでは、モジュール間の依存関係を`require`文で表現する。開発者がモジュール名から実際のファイルを特定し、定義へジャンプしたり、自動補完でモジュールを挿入したりする際に、正確なパス解決が不可欠である。この機能がなければ、大規模プロジェクトでのコードナビゲーションが著しく困難になる。

**機能の利用シーン**：
- `require "module.name"` の `module.name` から実ファイルへジャンプする時
- コード補完で利用可能なモジュール一覧を表示する時
- 自動requireでモジュールを挿入する際のパス生成時
- ファイルリネーム時のrequireパス自動更新時

**主要な処理内容**：
1. 設定された`Lua.runtime.path`パターンに基づいてモジュール名をファイルパスに変換
2. ワークスペース内およびライブラリパス内からマッチするファイルを検索
3. メタファイル（組み込み定義）の特別処理
4. プラグインによるカスタムrequire解決のサポート
5. キャッシュによる検索結果の高速化

**関連システム・外部連携**：
- ワークスペース管理システムとの連携（スコープ管理）
- 設定管理システムとの連携（パス設定の取得）
- プラグインシステムとの連携（カスタム解決）
- ファイル管理システムとの連携（ファイル一覧取得）

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 33 | 自動require | 主画面 | requireステートメントを自動追加する際のパス解決 |

## 機能種別

データ変換 / パス解決処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | uri | Yes | 現在のファイルのURI | 有効なファイルURI |
| name | string | Yes | requireで指定されたモジュール名 | 文字列型であること |
| path | string | Conditional | ファイルの絶対パス（getVisiblePath用） | 有効なファイルパス |

### 入力データソース

- LSPクライアントからのリクエスト
- 設定ファイル（.luarc.json等）からのパス設定
- ワークスペースのファイル一覧

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| uris | uri[] | マッチするファイルのURI配列 |
| searcherMap | table<uri, string> | 各URIに対応するsearcherパターン |
| visibleResults | require-manager.visibleResult[] | パスから可能なrequire名の一覧 |

### 出力先

- LSPクライアントへのレスポンス
- 内部キャッシュへの保存

## 処理フロー

### 処理シーケンス

```
1. モジュール名の正規化
   └─ セパレータ設定に基づいてパスを変換
2. プラグインによるカスタム解決の試行
   └─ ResolveRequireイベントをディスパッチ
3. メタファイルの検索
   └─ 組み込み定義からの検索
4. runtime.pathパターンに基づく検索
   └─ 各パターンでファイル検索を実行
5. DLLファイルの検索
   └─ ネイティブモジュールの検索
6. 結果のキャッシュと返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始: findUrisByRequireName] --> B{キャッシュあり?}
    B -->|Yes| C[キャッシュから結果取得]
    B -->|No| D[searchUrisByRequireNameを実行]
    D --> E{プラグインで解決可能?}
    E -->|Yes| F[プラグイン結果を返却]
    E -->|No| G[メタファイルを検索]
    G --> H{メタファイル発見?}
    H -->|Yes| I[メタファイルURIを返却]
    H -->|No| J[runtime.pathでパターン検索]
    J --> K[各ファイルを順次チェック]
    K --> L[DLLファイルを検索]
    L --> M[結果をキャッシュ]
    M --> N[現在ファイルを除外して返却]
    C --> N
    F --> O[終了]
    I --> O
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-71-01 | セパレータ変換 | モジュール名のセパレータを設定値に基づいて変換 | 常時 |
| BR-71-02 | strict モード | pathStrictがtrueの場合、パスの先頭一致を厳密にチェック | Lua.runtime.pathStrict設定時 |
| BR-71-03 | メタファイル優先 | メタファイルが見つかった場合は他の検索をスキップ | メタファイル発見時 |
| BR-71-04 | 自己除外 | 検索元ファイル自身は結果から除外 | 常時 |

### 計算ロジック

**パス変換ロジック**:
```lua
-- 例: "aaa.bbb.ccc" と "?.lua" から "aaa/bbb/ccc.lua" を生成
local path = name:gsub('%' .. separator, '/')
local fspath = searcher:gsub('%?', path)
```

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

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

本機能はファイルシステム操作のみで、データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 検索失敗 | ファイルが見つからない | 空配列を返却 |
| - | 無効な名前 | nameがstring型でない | 空配列を返却 |

### リトライ仕様

リトライは行わない。ファイル変更時にキャッシュがクリアされ、次回検索時に再計算される。

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

トランザクション管理は不要。読み取り専用の検索処理。

## パフォーマンス要件

- キャッシュにより同一モジュール名の2回目以降の検索は即時応答
- ファイル変更時にキャッシュをクリアして整合性を保持
- ワークスペース全体のファイル走査は初回のみ

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

- ワークスペース外のファイルへのアクセスは制限される
- プラグインによるカスタム解決はユーザー承認が必要

## 備考

- 設定変更（requireSeparator, runtime.path, pathStrict）時にキャッシュがクリアされる
- プラットフォーム（Windows/Unix）によりパスセパレータの正規化が異なる

---

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

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

### 推奨読解順序

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

まず、require-managerクラスの構造を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | require-path.lua | `script/workspace/require-path.lua` | 13-21行目: require-managerクラスの定義、nameMap/visibleCache/requireCacheの役割 |

**読解のコツ**: `---@class`アノテーションでクラス構造が定義されている。`mt`はメタテーブルとして使用される。

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

外部から呼び出される公開関数を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | require-path.lua | `script/workspace/require-path.lua` | 250-267行目: m.getVisiblePath, m.findUrisByRequireNameが公開API |

**主要処理フロー**:
1. **250-256行目**: getVisiblePath - パスからrequire名を逆算
2. **258-268行目**: findUrisByRequireName - require名からURIを検索

#### Step 3: 検索ロジックを理解する

実際の検索処理の詳細を確認。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | require-path.lua | `script/workspace/require-path.lua` | 150-216行目: searchUrisByRequireName - 実際の検索処理 |

**主要処理フロー**:
- **163-167行目**: プラグインによるカスタム解決の試行
- **169-180行目**: メタファイルの検索
- **182-204行目**: runtime.pathパターンによる検索
- **206-213行目**: DLLファイルの検索

#### Step 4: パス変換ロジックを理解する

モジュール名とファイルパスの相互変換。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | require-path.lua | `script/workspace/require-path.lua` | 34-58行目: getRequireNameByPath - パスからrequire名を生成 |
| 4-2 | require-path.lua | `script/workspace/require-path.lua` | 60-125行目: getRequireResultByPath - パスから全require名候補を取得 |

#### Step 5: キャッシュ管理を理解する

設定変更・ファイル変更時のキャッシュクリア。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | require-path.lua | `script/workspace/require-path.lua` | 300-314行目: files.watch, config.watchによるキャッシュ管理 |

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

```
m.findUrisByRequireName (公開API)
    │
    ├─ scope.getScope
    │      └─ スコープ取得
    │
    └─ mt:findUrisByRequireName
           │
           ├─ キャッシュ確認
           │
           └─ mt:searchUrisByRequireName
                  │
                  ├─ plugin.dispatch('ResolveRequire')
                  │      └─ プラグインによるカスタム解決
                  │
                  ├─ vm.isMetaFile / vm.getMetaName
                  │      └─ メタファイル検索
                  │
                  ├─ files.eachFile
                  │      └─ ワークスペースファイル走査
                  │
                  └─ files.eachDll
                         └─ DLLファイル走査
```

### データフロー図

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

モジュール名 ─────────▶ セパレータ変換 ─────────▶ 検索パス生成
  "module.name"              │
                             ▼
                      プラグイン解決試行
                             │
                             ▼
                      メタファイル検索
                             │
                             ▼
                      runtime.path検索
                             │
                             ▼
                      DLL検索
                             │
                             ▼
                      結果キャッシュ ─────────▶ URI配列
                                               [file:///path/to/module.lua]
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| require-path.lua | `script/workspace/require-path.lua` | ソース | requireパス解決のメインモジュール |
| scope.lua | `script/workspace/scope.lua` | ソース | ワークスペーススコープ管理 |
| files.lua | `script/files.lua` | ソース | ファイル管理・走査機能 |
| config.lua | `script/config/config.lua` | ソース | 設定値の取得 |
| plugin.lua | `script/plugin.lua` | ソース | プラグインディスパッチ |
| file-uri.lua | `script/file-uri.lua` | ソース | ファイルパスとURIの変換 |
