# 機能設計書 37-スペルチェック (spell-check)

## 概要

本ドキュメントは、Lua Language Serverにおける「スペルチェック機能」の設計詳細を記載したものである。識別子（変数名、関数名、コメントなど）のスペルミスを検出し、開発者にコードの品質向上と可読性向上を支援する診断機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
コード内の識別子やコメントにスペルミスがあると、コードの可読性が低下し、他の開発者が理解しにくくなる。また、一貫性のない命名は保守性の悪化につながる。本機能は、スペルミスを自動検出し、正しいスペル候補を提示することで、コード品質の向上を支援する。

**機能の利用シーン**：
- コード記述中のリアルタイムスペルチェック
- コードレビュー時の命名規則チェック
- ドキュメント生成前の品質チェック

**主要な処理内容**：
1. 対象ファイルのテキストを取得する
2. `spell.spellCheck`でスペルチェックを実行する
3. 診断情報の位置をLSPフォーマットに変換する
4. スペルミス箇所と修正候補を診断として報告する

**関連システム・外部連携**：
- LSP (Language Server Protocol)クライアント（VSCode等のエディタ）との連携
- code_formatモジュールによるスペルチェック機能
- 辞書ファイル（dictionary.txt、lua_dict.txt）

**権限による制御**：
- 設定`Lua.diagnostics.disable`で本診断を無効化可能
- 設定`Lua.spell.dict`でカスタム辞書を追加可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 診断情報 | 補助機能 | 識別子のスペルミスを検出 |

## 機能種別

バリデーション / 静的解析 / 診断

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 診断対象ファイルのURI | 有効なファイルURIであること |
| callback | function | Yes | 診断結果を受け取るコールバック関数 | - |

### 入力データソース

- ファイルシステムから読み込まれたLuaソースコード（originText）
- `config.get(uri, 'Lua.spell.dict')`からカスタム辞書
- 基本辞書ファイル（METAPATH/spell/dictionary.txt）
- Lua辞書ファイル（METAPATH/spell/lua_dict.txt）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | エラー位置の開始オフセット |
| finish | integer | エラー位置の終了オフセット |
| message | string | 診断メッセージ（スペルミス内容） |
| data | table | 修正候補などの追加データ |

### 出力先

- LSPクライアントへの診断通知（`textDocument/publishDiagnostics`）
- エディタ上でのインライン警告表示

## 処理フロー

### 処理シーケンス

```
1. ファイル状態の取得
   └─ files.getState(uri)でファイル状態を取得
2. オリジナルテキストの取得
   └─ state.originTextで元テキストを取得
3. スペルチェックの実行
   └─ spell.spellCheck(uri, text)
4. 辞書の初期化（初回のみ）
   └─ spell.initDictionary()
5. 結果の変換
   └─ converter.unpackPositionで位置変換
6. 診断結果の報告
   └─ callback({ start, finish, message, data })
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ファイル状態を取得]
    B --> C{状態が存在するか?}
    C -->|No| D[終了]
    C -->|Yes| E[originTextを取得]
    E --> F[spell.spellCheck実行]
    F --> G{status == true?}
    G -->|No| H[エラーログ出力]
    H --> D
    G -->|Yes| I{diagnosticInfosあり?}
    I -->|No| D
    I -->|Yes| J[診断情報をループ]
    J --> K[位置変換]
    K --> L[callback呼び出し]
    L --> M{次の診断あり?}
    M -->|Yes| J
    M -->|No| D
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-37-01 | 辞書初期化 | 初回チェック時に辞書を自動ロード | _dictionaryLoaded == false |
| BR-37-02 | 基本辞書 | METAPATH/spell/dictionary.txtを使用 | 常時 |
| BR-37-03 | Lua辞書 | METAPATH/spell/lua_dict.txtを使用 | 常時 |
| BR-37-04 | カスタム辞書 | Lua.spell.dict設定で追加辞書を指定 | 設定時 |
| BR-37-05 | 位置変換 | LSPの位置フォーマットに変換 | converter.unpackPosition |

### 計算ロジック

#### スペルチェック処理

```lua
-- spell.spellCheck(uri, text)
function m.spellCheck(uri, text)
    if not m._dictionaryLoaded then
        m.initDictionary()
        m._dictionaryLoaded = true
    end

    local tempDict = config.get(uri, 'Lua.spell.dict')

    return codeFormat.spell_analysis(uri, text, tempDict)
end
```

#### 辞書初期化

```lua
function m.initDictionary()
    local basicDictionary = fs.path(METAPATH) / "spell/dictionary.txt"
    local luaDictionary = fs.path(METAPATH) / "spell/lua_dict.txt"

    m.loadDictionaryFromFile(basicDictionary:string())
    m.loadDictionaryFromFile(luaDictionary:string())
    pformatting.updateNonStandardSymbols(...)
end
```

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ファイル状態なし | files.getState(uri)がnilを返す場合 | 処理を中断して正常終了 |
| - | スペルチェック失敗 | status == falseの場合 | エラーをログ出力して終了 |

### リトライ仕様

リトライは行わない。ファイルが再度編集された際に自動的に再診断される。

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

該当なし（読み取り専用処理）

## パフォーマンス要件

- 単一ファイルの診断は通常0.5秒以内に完了すること
- 辞書は初回ロード後キャッシュされる

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

- ユーザーコードの読み取りのみを行い、ファイルシステムへの書き込みは行わない
- 辞書ファイルは信頼できるソースからのみロード

## 備考

- code_formatモジュール（C++拡張）が必要
- 辞書ファイルが存在しない場合、スペルチェック機能は無効になる

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | spell.lua | `script/provider/spell.lua` | スペルチェックのメインモジュール |

**読解のコツ**: code_formatモジュール（C++拡張）への委譲が中心。辞書管理とAPI呼び出しを理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | spell-check.lua | `script/core/diagnostics/spell-check.lua` | 診断エントリーポイント |

**主要処理フロー**:
1. **8-12行目**: ファイル状態とテキスト取得
2. **15行目**: spell.spellCheck(uri, text)実行
3. **17-23行目**: エラーハンドリング
4. **25-33行目**: 診断結果のコールバック

#### Step 3: スペルチェックモジュールを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | spell.lua | `script/provider/spell.lua` | spellCheck関数 |

**主要処理フロー**:
- **1-4行目**: code_formatモジュールのロード確認
- **12-13行目**: 辞書ファイルロード関数
- **24-33行目**: spellCheck関数 - 辞書初期化とスペル分析
- **35-40行目**: getSpellSuggest関数 - 修正候補取得
- **42-49行目**: initDictionary関数 - 辞書の初期化

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

```
script/core/diagnostics/init.lua (診断エントリー)
    │
    ├─ require('core.diagnostics.spell-check')
    │      │
    │      ├─ files.getState(uri)
    │      │      └─ state.originText
    │      │
    │      ├─ spell.spellCheck(uri, text)
    │      │      │
    │      │      ├─ spell.initDictionary() [初回のみ]
    │      │      │      │
    │      │      │      ├─ codeFormat.spell_load_dictionary_from_path()
    │      │      │      │      ├─ dictionary.txt
    │      │      │      │      └─ lua_dict.txt
    │      │      │      │
    │      │      │      └─ pformatting.updateNonStandardSymbols()
    │      │      │
    │      │      └─ codeFormat.spell_analysis(uri, text, tempDict)
    │      │
    │      └─ converter.unpackPosition(state, position)
    │
    └─ callback(result)
```

### データフロー図

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

Luaソースコード ───▶ files.getState() ───▶ originText
      │                                          │
      │                                          ▼
      │                      spell.spellCheck(uri, text)
      │                                          │
      │                            ┌─────────────┴─────────────┐
      │                            │                            │
      │                            ▼                            ▼
      │                     辞書初期化                    スペル分析
      │                            │                            │
      │                            ▼                            ▼
辞書ファイル ───────▶ dictionary.txt        codeFormat.spell_analysis
                     lua_dict.txt                    │
                            │                        │
                            └──────────┬─────────────┘
                                       │
                                       ▼
                            diagnosticInfos ───▶ 位置変換
                                       │
                                       ▼
                            LSP診断通知 ───▶ エディタ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| spell-check.lua | `script/core/diagnostics/spell-check.lua` | ソース | スペルチェック診断のエントリー |
| spell.lua | `script/provider/spell.lua` | ソース | スペルチェックモジュール |
| init.lua | `script/core/diagnostics/init.lua` | ソース | 診断処理のエントリーポイント |
| converter.lua | `script/proto/converter.lua` | ソース | 位置変換ユーティリティ |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| formatting.lua | `script/provider/formatting.lua` | ソース | NonStandardSymbols設定 |
| dictionary.txt | `meta/spell/dictionary.txt` | 辞書 | 基本英語辞書 |
| lua_dict.txt | `meta/spell/lua_dict.txt` | 辞書 | Lua専用辞書 |
| log.lua | `script/log.lua` | ソース | ログ出力 |
