# 機能設計書 38-コードスタイル (codestyle-check)

## 概要

本ドキュメントは、Lua Language Serverにおける「コードスタイルチェック機能」の設計詳細を記載したものである。コーディングスタイルの一貫性を検証し、チームの規約に沿ったコード記述を支援する診断機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：
チーム開発において、コーディングスタイルの統一は可読性とメンテナンス性の向上に不可欠である。インデント、空白の使い方、行の長さなどのスタイルルールをコードで自動検証することで、コードレビューの負荷軽減とコード品質の均一化を実現する。本機能は、EditorConfig等の設定に基づいてコードスタイルを検証し、違反箇所を報告する。

**機能の利用シーン**：
- コード記述中のリアルタイムスタイルチェック
- コードレビュー前の自動スタイル検証
- CI/CDパイプラインでのスタイルチェック

**主要な処理内容**：
1. 対象ファイルのテキストを取得する
2. code_formatモジュールの設定を更新する
3. `codeFormat.diagnose_file`でスタイルチェックを実行する
4. 診断情報の位置をLSPフォーマットに変換する
5. スタイル違反箇所を診断として報告する

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

**権限による制御**：
- 設定`Lua.diagnostics.disable`で本診断を無効化可能
- 設定`Lua.format.defaultConfig`でデフォルト設定を指定可能

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 26 | 診断情報 | 補助機能 | コーディングスタイルの検証 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

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

### 入力データソース

- ファイルシステムから読み込まれたLuaソースコード（originText）
- EditorConfigファイル（.editorconfig）
- `config.get(uri, 'Lua.format.defaultConfig')`からデフォルト設定

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| start | integer | エラー位置の開始オフセット |
| finish | integer | エラー位置の終了オフセット |
| message | string | 診断メッセージ（スタイル違反内容） |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. ファイル状態の取得
   └─ files.getState(uri)でファイル状態を取得
2. code_formatモジュールの確認
   └─ pcall(require, 'code_format')でモジュール存在確認
3. 設定の更新
   └─ pformatting.updateConfig(uri)
4. スタイルチェックの実行
   └─ codeFormat.diagnose_file(uri, text)
5. 結果の変換
   └─ converter.unpackPositionで位置変換
6. 診断結果の報告
   └─ callback({ start, finish, message })
```

### フローチャート

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

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-38-01 | モジュール必須 | code_formatモジュールが必須 | pcallでロード確認 |
| BR-38-02 | 設定更新 | pformatting.updateConfigで設定同期 | 診断前に実行 |
| BR-38-03 | EditorConfig | .editorconfigファイルから設定読み込み | ファイル存在時 |
| BR-38-04 | デフォルト設定 | Lua.format.defaultConfigを優先適用 | 設定時 |
| BR-38-05 | 位置変換 | LSPの位置フォーマットに変換 | converter.unpackPosition |

### 計算ロジック

#### 設定更新処理

```lua
-- pformatting.updateConfig(uri)
function m.updateConfig(uri)
    if not m.loadedDefaultConfig then
        m.loadedDefaultConfig = true
        codeFormat.set_default_config(config.get(uri, 'Lua.format.defaultConfig'))
        m.updateNonStandardSymbols(config.get(nil, 'Lua.runtime.nonstandardSymbol'))
    end

    -- .editorconfigを探索してロード
    local currentUri = uri
    while true do
        currentUri = currentUri:match('^(.+)/[^/]*$')
        if not currentUri or loadedUris[currentUri] then
            return
        end
        loadedUris[currentUri] = true

        local editorConfigFSPath = fs.path(currentPath) / '.editorconfig'
        if fs.exists(editorConfigFSPath) then
            loadedUris[currentUri] = editorConfigFSPath
            codeFormat.update_config(updateType.Created, currentUri, editorConfigFSPath:string())
        end
    end
end
```

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

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

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

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

## パフォーマンス要件

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

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

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

## 備考

- code_formatモジュール（C++拡張）が必要
- EditorConfigの標準仕様に準拠した設定が利用可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | formatting.lua | `script/provider/formatting.lua` | フォーマット/スタイル設定管理 |

**読解のコツ**: code_formatモジュールとEditorConfigの設定同期が重要。updateConfig関数でディレクトリ階層を遡って.editorconfigを探索する。

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

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

**主要処理フロー**:
1. **8-12行目**: ファイル状態とテキスト取得
2. **15-18行目**: code_formatモジュールのロード確認
3. **20行目**: pformatting.updateConfig(uri)で設定更新
4. **22行目**: codeFormat.diagnose_file(uri, text)実行
5. **24-30行目**: エラーハンドリング
6. **32-39行目**: 診断結果のコールバック

#### Step 3: 設定管理を理解する

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

**主要処理フロー**:
- **15-19行目**: updateType定数の定義（Created/Changed/Deleted）
- **21-33行目**: filewatch.eventで.editorconfigの変更監視
- **38-45行目**: loadedDefaultConfigでデフォルト設定の初期化
- **48-75行目**: ディレクトリ階層を遡って.editorconfigを探索
- **79-91行目**: updateNonStandardSymbolsでC-likeコメント等の対応

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

```
script/core/diagnostics/init.lua (診断エントリー)
    │
    ├─ require('core.diagnostics.codestyle-check')
    │      │
    │      ├─ files.getState(uri)
    │      │      └─ state.originText
    │      │
    │      ├─ pcall(require, 'code_format')
    │      │
    │      ├─ pformatting.updateConfig(uri)
    │      │      │
    │      │      ├─ codeFormat.set_default_config()
    │      │      │
    │      │      └─ codeFormat.update_config()
    │      │             └─ .editorconfig読み込み
    │      │
    │      ├─ codeFormat.diagnose_file(uri, text)
    │      │
    │      └─ converter.unpackPosition(state, position)
    │
    └─ callback(result)
```

### データフロー図

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

Luaソースコード ───▶ files.getState() ───▶ originText
      │                                          │
      │                                          ▼
      │                    pformatting.updateConfig(uri)
      │                                          │
      │                           ┌──────────────┴──────────────┐
      │                           │                              │
      │                           ▼                              ▼
.editorconfig ───────▶ codeFormat.update_config()   codeFormat.set_default_config()
                                  │                              │
                                  └──────────────┬───────────────┘
                                                 │
                                                 ▼
                              codeFormat.diagnose_file(uri, text)
                                                 │
                                                 ▼
                              diagnosticInfos ───▶ 位置変換
                                                 │
                                                 ▼
                              LSP診断通知 ───▶ エディタ表示
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| codestyle-check.lua | `script/core/diagnostics/codestyle-check.lua` | ソース | コードスタイル診断のエントリー |
| formatting.lua | `script/provider/formatting.lua` | ソース | フォーマット設定管理 |
| init.lua | `script/core/diagnostics/init.lua` | ソース | 診断処理のエントリーポイント |
| converter.lua | `script/proto/converter.lua` | ソース | 位置変換ユーティリティ |
| files.lua | `script/files.lua` | ソース | ファイル状態管理 |
| config.lua | `script/config/config.lua` | ソース | 設定値取得 |
| filewatch.lua | `script/filewatch.lua` | ソース | ファイル監視 |
| log.lua | `script/log.lua` | ソース | ログ出力 |
