# 機能設計書 68-ファイルキャッシュ

## 概要

本ドキュメントは、Lua Language Serverにおける「ファイルキャッシュ」機能の設計を記述する。本機能は、開いているファイルのテキスト内容と解析状態を管理し、効率的なファイルアクセスと重複解析の回避を実現する。

### 本機能の処理概要

ファイルキャッシュ機能は、ワークスペース内のLuaファイルのテキスト内容、パース済みAST、各種メタデータを一元管理する。ファイルの追加・更新・削除をトラッキングし、変更時には関連するキャッシュを無効化する。

**業務上の目的・背景**：大規模なLuaプロジェクトでは、ファイル数が数千に及ぶことがある。毎回ファイルを読み直して解析していては処理が遅くなる。ファイルキャッシュにより、一度読み込んだファイルの内容と解析結果を保持し、必要な時に即座にアクセスできるようにする。

**機能の利用シーン**：
- ファイルを開いた時のテキスト読み込みとキャッシュ
- 編集時のキャッシュ更新
- 補完・ホバー等の機能実行時のキャッシュ参照
- ファイルを閉じた時のキャッシュ管理
- ワークスペース全体のファイル列挙

**主要な処理内容**：
1. ファイルのオープン/クローズ管理
2. テキスト内容の設定・取得
3. パース済みASTの管理
4. ファイル変更時のキャッシュ無効化
5. グローバルバージョン管理
6. ファイルURI正規化
7. DLLファイルの特別処理

**関連システム・外部連携**：
- workspace/：ワークスペース管理モジュールとの連携
- filewatch.lua：ファイル変更監視との連携
- parser/：パーサーの呼び出しとAST保持
- LSPプロトコル：didOpen/didClose/didChange等のハンドリング

**権限による制御**：本機能に権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はバックグラウンドで動作し、専用の画面は存在しない |

## 機能種別

データ管理 / キャッシュ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | ファイルURI | 有効なfile://形式 |
| text | string | No | ファイルテキスト | - |
| isTrust | boolean | No | 信頼できるソースか | - |

### 入力データソース

- LSPプロトコル経由のテキスト（didOpen/didChange）
- ファイルシステムからの読み込み

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| file | table | ファイル情報オブジェクト |
| file.uri | string | ファイルURI |
| file.text | string | テキスト内容 |
| file.state | parser.state | パース済み状態 |
| file.version | integer | バージョン番号 |
| file.cache | table | 機能別キャッシュ |

### 出力先

メモリ上のファイルマップ（m.fileMap）

## 処理フロー

### 処理シーケンス

```
1. ファイルオープン
   └─ m.open(uri)でオープン状態を記録
2. テキスト設定
   ├─ エンコーディング変換
   ├─ プラグインによる変換
   └─ キャッシュへの保存
3. AST取得
   ├─ キャッシュ確認
   ├─ なければコンパイル
   └─ キャッシュに保存
4. ファイル更新
   ├─ 古いキャッシュの無効化
   ├─ 新しいテキストの設定
   └─ グローバルバージョンの更新
5. ファイルクローズ
   ├─ オープン状態の解除
   └─ 参照がなければ削除
6. ファイル削除
   └─ キャッシュからの完全削除
```

### フローチャート

```mermaid
flowchart TD
    A[ファイル操作] --> B{操作の種類}
    B -->|open| C[オープン状態を記録]
    B -->|setText| D[テキスト設定処理]
    B -->|getState| E[AST取得処理]
    B -->|close| F[クローズ処理]
    B -->|remove| G[削除処理]

    D --> D1[エンコーディング変換]
    D1 --> D2[プラグイン変換]
    D2 --> D3[キャッシュ保存]
    D3 --> D4[バージョン更新]

    E --> E1{キャッシュあり?}
    E1 -->|Yes| E2[キャッシュ返却]
    E1 -->|No| E3[コンパイル実行]
    E3 --> E4[キャッシュに保存]
    E4 --> E2

    F --> F1[オープン状態解除]
    F1 --> F2{参照あり?}
    F2 -->|Yes| F3[保持]
    F2 -->|No| G

    G --> G1[fileMap削除]
    G1 --> G2[stateMap削除]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | オープンファイル優先 | 開いているファイルは常にキャッシュを保持 | m.isOpen(uri) == true |
| BR-02 | 参照カウント | 参照がある限りキャッシュを保持 | file.ref > 0 |
| BR-03 | 信頼ソース | 信頼ソースからのテキストは優先される | isTrust == true |
| BR-04 | グローバルバージョン | ファイル変更時にグローバルバージョンを更新 | setText/remove時 |
| BR-05 | プリロードサイズ制限 | 大きなファイルはプリロードをスキップ | 設定値を超える場合 |

### 計算ロジック

特になし

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

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

本機能はデータベースを使用しない（メモリ上でキャッシュ操作を行う）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| WORKSPACE_SKIP_HUGE_FILE | Warning | ファイルサイズが10MBを超える | 設定を調整 |
| WORKSPACE_SKIP_LARGE_FILE | Info | プリロードサイズ制限を超える | 設定を調整 |

### リトライ仕様

リトライは不要

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

トランザクション管理は不要（メモリ上の操作）

## パフォーマンス要件

- ファイルテキストの取得は1ms以内
- キャッシュヒット時のAST取得は1ms以内
- キャッシュミス時のAST取得は前回コンパイル時間に依存

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

- 大きなファイルによるメモリ枯渇の防止（10MB制限）
- エンコーディング変換によるセキュリティリスクの軽減

## 備考

- files.luaはLua Language Serverの中核モジュールの一つ
- ファイルキャッシュはワークスペース全体で共有される
- DLLファイルは特別な処理が適用される

---

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

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

### 推奨読解順序

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

まず、ファイルキャッシュのデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | files.lua | `script/files.lua` | `@class file`の定義（20-35行目） |
| 1-2 | files.lua | `script/files.lua` | `@class files`の定義（36-38行目） |

**読解のコツ**: `file`オブジェクトは以下のフィールドを持つ：
- `uri`: ファイルURI
- `text`: テキスト内容
- `originText`: 元のテキスト（変換前）
- `state`: パース済み状態（parser.state）
- `version`: バージョン番号
- `cache`: 機能別キャッシュ
- `ref`: 参照カウント
- `trusted`: 信頼ソースフラグ

#### Step 2: 主要な関数を理解する

ファイル操作の主要関数を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | files.lua | `script/files.lua` | `m.open`関数（120-125行目） |
| 2-2 | files.lua | `script/files.lua` | `m.close`関数（128-141行目） |
| 2-3 | files.lua | `script/files.lua` | `m.setText`関数（233-303行目） |
| 2-4 | files.lua | `script/files.lua` | `m.getState`関数（736-743行目） |

**主要処理フロー**:
- **m.open**: オープン状態をm.openMapに記録
- **m.close**: オープン状態を解除、参照がなければ削除
- **m.setText**: テキストを設定、キャッシュを更新
- **m.getState**: ASTを取得（キャッシュまたはコンパイル）

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

キャッシュの生成と無効化を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | files.lua | `script/files.lua` | `m.removeState`関数（223-226行目） |
| 3-2 | files.lua | `script/files.lua` | `m.compileState`関数（673-725行目） |
| 3-3 | files.lua | `script/files.lua` | `m.compileStateThen`関数（546-581行目） |

**主要処理フロー**:
- **m.removeState**: ASTキャッシュを削除
- **m.compileState**: ファイルをコンパイルしてASTを取得
- **m.compileStateThen**: コンパイル後処理（LuaDoc統合、キャッシュ設定）

#### Step 4: ファイル列挙を理解する

ワークスペース内のファイル列挙を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | files.lua | `script/files.lua` | `m.getAllUris`関数（489-503行目） |
| 4-2 | files.lua | `script/files.lua` | `m.eachFile`関数（507-522行目） |

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

```
files (ファイル管理モジュール)
    │
    ├─ m.open / m.close
    │      └─ オープン状態管理
    │
    ├─ m.setText
    │      ├─ pluginOnSetText (プラグイン変換)
    │      ├─ m.removeState (キャッシュ無効化)
    │      └─ m.onWatch('update') (イベント発火)
    │
    ├─ m.getState
    │      └─ m.compileState
    │             ├─ parser.compile (パーサー呼び出し)
    │             ├─ pluginOnTransformAst (プラグイン処理)
    │             └─ m.compileStateThen
    │                    └─ parser.luadoc (LuaDoc解析)
    │
    └─ m.remove
           ├─ m.removeState
           └─ m.onWatch('remove')
```

### データフロー図

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

didOpen(uri, text)
        │
        ▼
  m.open(uri)          ───▶  m.openMap[uri] = {...}
        │
        ▼
  m.setText(uri, text) ───▶  エンコーディング変換
        │                    ↓
        │                    プラグイン変換
        │                    ↓
        │                    m.fileMap[uri] = file
        │
        ▼
  m.getState(uri)      ───▶  キャッシュ確認
        │                    ↓
        │                    コンパイル（必要時）
        │                    ↓
        ▼                    m.stateMap[uri] = state
  state (AST)          ───▶  後続処理へ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| files.lua | `script/files.lua` | ソース | ファイルキャッシュ管理のメイン |
| filewatch.lua | `script/filewatch.lua` | ソース | ファイル変更監視 |
| workspace.lua | `script/workspace/workspace.lua` | ソース | ワークスペース管理 |
| parser.lua | `script/parser.lua` | ソース | パーサーモジュール |
| encoder.lua | `script/encoder.lua` | ソース | エンコーディング変換 |
| file-uri.lua | `script/file-uri.lua` | ソース | URI変換ユーティリティ |
