# 機能設計書 47-カスタム診断

## 概要

本ドキュメントは、clojure-lspの「カスタム診断」機能の設計を詳細に記載する。この機能は、ユーザー定義のリンタールールをSCI（Small Clojure Interpreter）で実行し、カスタム診断を生成する拡張機能である。

### 本機能の処理概要

**業務上の目的・背景**：プロジェクト固有のコーディング規約やドメイン特有のルールは、汎用的な静的解析ツールではカバーできないことがある。この機能により、Clojureコードでカスタムリンターを記述し、プロジェクト固有の診断ルールを実装できる。

**機能の利用シーン**：プロジェクトの依存関係にカスタムリンターを含め、設定で有効化すると、ファイル保存時やプロジェクト読み込み時に自動実行される。

**主要な処理内容**：
1. 設定からカスタムリンター定義を取得
2. SCIインタプリタでリンターコードをロード
3. 各リンター関数を実行し、診断を収集
4. 診断形式に変換して表示

**関連システム・外部連携**：SCI（Small Clojure Interpreter）、カスタムリンターAPI。

**権限による制御**：特になし。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | エディタ | 主画面 | 診断結果の表示 |

## 機能種別

静的解析 / 診断 / プラグイン

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uris | Array[String] | Yes | 解析対象ファイルURIの配列 | 有効なファイルURI |

### 入力データソース

- 設定（:linters :custom）
- クラスパス上のリンターコード（clojure-lsp.exports/linters/）
- clojure-lsp解析データ（db）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| diagnostics | Map | URI毎の診断配列 |
| diagnostics[uri] | Array | LSP診断オブジェクトの配列 |

### 出力先

- LSP textDocument/publishDiagnostics 通知（変換後）

## 処理フロー

### 処理シーケンス

```
1. カスタムリンター設定の取得
   └─ settings/get [:linters :custom]
2. 各リンター毎に処理
   └─ SCIコンテキストを初期化
   └─ リンターコードをロード（クラスパスから）
   └─ リンター関数を実行
3. 診断の収集
   └─ reg-diagnostic! コールバックで収集
   └─ 必須フィールドをバリデーション
4. 診断形式に変換
   └─ custom-diagnostic->lsp
5. 結果をマージ
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{カスタムリンター設定あり?}
    B -->|いいえ| Z[空Map返却]
    B -->|はい| C[リンター毎にループ]
    C --> D{レベル有効?}
    D -->|いいえ| C
    D -->|はい| E[SCIコンテキスト初期化]
    E --> F[リンターコードロード]
    F --> G[リンター関数実行]
    G --> H[診断収集]
    H --> C
    C -->|完了| I[結果マージ]
    I --> J[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | レベル有効性 | :level が有効なレベル（:error, :warning, :info, :hint）の場合のみ実行 | 常時 |
| BR-02 | 必須フィールド | :uri, :range, :level, :message, :source, :code が必須 | 診断登録時 |
| BR-03 | 範囲必須フィールド | :row, :col, :end-row, :end-col が必須 | 診断登録時 |
| BR-04 | 名前空間変換 | fqns からパスを計算（clojure-lsp.exports/linters/...） | ロード時 |

### 計算ロジック

リンターパス計算：
```clojure
(let [package (namespace-munge (name namespace))
      path (str "clojure-lsp.exports/linters/"
                (string/replace package "." "/") ".clj")]
  ...)
```

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 診断格納 | :diagnostics :custom | MERGE | URI毎の診断配列をマージ |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | ロードエラー | リンターコード読み込み失敗 | エラーログ出力、スキップ |
| N/A | 実行エラー | リンター実行時例外 | エラーログ出力、スキップ |
| N/A | バリデーションエラー | 必須フィールド欠落 | 警告ログ出力、診断スキップ |

### リトライ仕様

リトライなし

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

アトム操作による排他制御。

## パフォーマンス要件

- リンター実行時間はリンターの実装依存
- SCIの起動オーバーヘッドあり

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

- SCIサンドボックス環境で実行（任意コード実行制限）
- クラス制限（Exception, System, File等のみ許可）

## 備考

- カスタムリンターAPIはclojure-lsp.custom-linters-api名前空間で提供
- rewrite-clj の基本操作が利用可能

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | custom.clj | `lib/src/clojure_lsp/feature/diagnostics/custom.clj` | 診断の必須フィールド、SCIコンテキストを理解 |
| 1-2 | custom_linters_api.clj | `lib/src/clojure_lsp/custom_linters_api.clj` | カスタムリンターAPIを理解 |

**読解のコツ**: required-fields と SCIの名前空間マッピングを把握する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | custom.clj | `lib/src/clojure_lsp/feature/diagnostics/custom.clj` | analyze-uris!, analyze-uri! |

**主要処理フロー**:
- **127-147行目**: `analyze-uris!` - メイン処理
- **149-151行目**: `analyze-uri!` - 単一ファイル処理

#### Step 3: リンター実行を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | custom.clj | `lib/src/clojure_lsp/feature/diagnostics/custom.clj` | analyze 関数 |

**主要処理フロー**:
- **49-125行目**: `analyze` - リンター実行ロジック
- **51-94行目**: SCIコンテキスト初期化
- **89-93行目**: :load-fn でクラスパスからコードロード
- **97-102行目**: reg-diagnostic! コールバック定義
- **108-117行目**: SCIでのリンター関数評価と実行

#### Step 4: カスタムリンターAPIを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | custom_linters_api.clj | `lib/src/clojure_lsp/custom_linters_api.clj` | api-fns マップ |

**主要処理フロー**:
- **9-137行目**: 各API関数の定義
- **139-159行目**: `api-fns` - SCIに公開する関数マップ

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

```
startup/initialize-project (並列実行)
    │
    └─ custom/analyze-paths!
           │
           └─ analyze-uris!
                  │
                  └─ analyze (各リンター毎)
                         │
                         ├─ sci/init (SCIコンテキスト初期化)
                         │      │
                         │      ├─ clojure-lsp.custom-linters-api
                         │      ├─ rewrite-clj.zip
                         │      └─ rewrite-clj.node
                         │
                         ├─ :load-fn (クラスパスからロード)
                         │      └─ file-content-from-classpath
                         │
                         ├─ sci/eval-string* (リンター関数取得)
                         │
                         └─ lint-fn (リンター実行)
                                │
                                └─ reg-diagnostic! (診断登録)

custom/db-with-results
    │
    └─ update :diagnostics :custom
```

### データフロー図

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

設定 :linters :custom ───▶ analyze-uris!
                           │
                           ▼
               ┌───────────┴───────────┐
               │                       │
        sci/init               file-content-from-classpath
               │                       │
               └───────────┬───────────┘
                           │
                           ▼
                    sci/eval-string*
                           │
                           ▼
                        lint-fn
                           │
                           ▼
                   reg-diagnostic!
                           │
                           ▼
                 custom-diagnostic->lsp
                           │
                           ▼
                  :diagnostics :custom
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| custom.clj | `lib/src/clojure_lsp/feature/diagnostics/custom.clj` | ソース | カスタム診断のメインロジック |
| custom_linters_api.clj | `lib/src/clojure_lsp/custom_linters_api.clj` | ソース | カスタムリンターAPI |
| diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | ソース | 診断統合 |
| settings.clj | `lib/src/clojure_lsp/settings.clj` | ソース | 設定管理 |
