# 通知設計書 13-textDocument/publishDiagnostics

## 概要

本ドキュメントは、clojure-lspにおける`textDocument/publishDiagnostics`通知の設計仕様を記載したものです。この通知はサーバーからクライアントへ送信される通知であり、コード解析で検出されたエラー、警告、情報メッセージをクライアントに公開します。

### 本通知の処理概要

`textDocument/publishDiagnostics`通知は、Clojureコードの静的解析結果（診断情報）をエディタに表示するための中核的な機能です。clj-kondo、clj-depend、カスタムリンターなど複数のソースからの診断結果を統合し、ユーザーにリアルタイムでコード品質フィードバックを提供します。

**業務上の目的・背景**：この通知はLSP標準仕様の一部であり、コード編集中にリアルタイムでエラーや警告を表示することで、開発者が問題を早期に発見・修正できるようにします。clojure-lspはclj-kondoとの統合により、未使用変数、構文エラー、型の不整合、依存関係の問題などを検出します。

**通知の送信タイミング**：以下のイベントで送信されます：
- ドキュメントが開かれたとき（didOpen）
- ドキュメントが変更されたとき（didChange後の解析完了時）
- 監視対象ファイルが変更されたとき（didChangeWatchedFiles）
- プロジェクト初期化完了後の一括診断

**通知の受信者**：エディタ（クライアント）がこの通知を受信し、該当するドキュメントの診断情報をUI上に表示します（波線、マーカー、問題パネルなど）。

**通知内容の概要**：通知には対象ドキュメントのURIと診断情報の配列が含まれます。各診断には位置（range）、重大度（severity）、メッセージ、ソース（clj-kondo/clojure-lsp/clj-depend）、コード、タグ（deprecatedや unnecessary）などが含まれます。

**期待されるアクション**：ユーザーはエディタ上に表示された診断情報を確認し、該当箇所のコードを修正することが期待されます。また、コードアクションで自動修正を適用することもできます。

## 通知種別

LSP通知（サーバー→クライアント）

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（core.asyncチャンネル経由、デバウンス付き） |
| 優先度 | 中 |
| リトライ | なし |

### 送信先決定ロジック

サーバーからクライアントへの一方向通知のため、送信先は接続されているエディタクライアントに固定されます。

## 通知テンプレート

### LSP通知の場合

| 項目 | 内容 |
|-----|------|
| メソッド名 | `textDocument/publishDiagnostics` |
| パラメータ | PublishDiagnosticsParams |
| レスポンス | なし（通知のため） |

### 本文テンプレート

```json
{
  "uri": "file:///path/to/file.clj",
  "diagnostics": [
    {
      "range": {
        "start": {"line": 10, "character": 5},
        "end": {"line": 10, "character": 15}
      },
      "severity": 2,
      "code": "unused-binding",
      "source": "clj-kondo",
      "message": "unused binding x",
      "tags": [1]
    }
  ]
}
```

### 添付ファイル

該当なし

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| uri | ドキュメントURI | 診断対象ファイル | Yes |
| diagnostics | 診断情報の配列 | find-diagnostics関数 | Yes |
| range | 診断位置 | clj-kondo findings / 各リンター | Yes |
| severity | 重大度（1=Error, 2=Warning, 3=Info, 4=Hint） | shared/level->severity | Yes |
| code | 診断コード | clj-kondo type / カスタム | Yes |
| source | 診断ソース | clj-kondo / clojure-lsp / clj-depend | Yes |
| message | 診断メッセージ | clj-kondo / 各リンター | Yes |
| tags | 診断タグ（1=Unnecessary, 2=Deprecated） | diagnostic-types-of-unnecessary-type等 | No |
| data | 追加データ（refers等） | clj-kondo findings | No |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| ドキュメント操作 | textDocument/didOpen | 常に | ファイルを開いた時 |
| ドキュメント操作 | textDocument/didChange | 解析完了後 | ファイル編集後（デバウンス25ms） |
| ファイル監視 | workspace/didChangeWatchedFiles | ファイルが存在する場合 | 外部変更検出時 |
| 初期化 | initialize完了後 | lint-project-files-after-startup?がtrue | プロジェクト全体の初期診断 |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| JARファイル | shared/jar-file?がtrueの場合、空配列を返却 |
| kondo-levelがoff | clj-kondoの診断をスキップ |
| depend-levelがoff | clj-dependの診断をスキップ |
| ns-exclude-regex一致 | 除外パターンに一致するネームスペースをスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[トリガー発生] --> B[診断チャンネルに送信]
    B --> C[デバウンス処理 25ms]
    C --> D[publish-diagnostic呼び出し]
    D --> E[find-diagnostics実行]
    E --> F{JARファイル?}
    F -->|Yes| G[空配列を返却]
    F -->|No| H[各リンター診断収集]
    H --> I[clj-kondo診断]
    H --> J[clj-depend診断]
    H --> K[built-in診断]
    H --> L[custom診断]
    I --> M[診断統合]
    J --> M
    K --> M
    L --> M
    G --> N[PublishDiagnosticsParams構築]
    M --> N
    N --> O[conform-or-log検証]
    O --> P[send-notification実行]
    P --> Q[終了]
```

## データベース参照・更新仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 備考 |
|-----------|------|------|
| db（アトム） | 診断データ・設定の参照 | インメモリ状態管理 |

### テーブル別参照項目詳細

#### db（アトム）

| 参照項目（カラム名） | 用途 | 取得条件 |
|-------------------|------|---------|
| :diagnostics :clj-kondo uri | clj-kondo診断結果 | URI指定 |
| :diagnostics :clj-depend namespace | clj-depend診断結果 | ネームスペース指定 |
| :diagnostics :built-in uri | 組み込み診断結果 | URI指定 |
| :diagnostics :custom uri | カスタム診断結果 | URI指定 |
| :documents uri :text | ドキュメントテキスト | 行分割用 |
| :settings :diagnostics :range-type | 範囲タイプ設定 | 診断範囲計算用 |
| :settings :linters :clj-kondo :level | clj-kondoレベル | off判定用 |
| :settings :linters :clj-depend :level | clj-dependレベル | off判定用 |
| :kondo-config :output :langs | 言語出力設定 | メッセージ付加用 |

### 更新テーブル一覧

| テーブル名 | 操作 | 概要 |
|-----------|------|------|
| なし | - | この通知自体では状態更新は行いません（診断収集時に更新済み） |

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| conform失敗 | 診断データの形式不正 | ログ出力して処理継続 |
| 無効なfinding | row/colがない | フィルタリングで除外、警告ログ |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | 0回 |
| リトライ間隔 | - |
| リトライ対象エラー | - |

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| デバウンス間隔 | 25ms |
| 1分あたり上限 | なし（デバウンスで制御） |
| 1日あたり上限 | なし |

### 配信時間帯

制限なし

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

診断情報にはファイルパスとコード位置が含まれますが、ローカルで動作するため特別なセキュリティ考慮は不要です。

## 備考

- 診断のタグ（1=Unnecessary, 2=Deprecated）はLSP仕様に準拠
- severity: 1=Error, 2=Warning, 3=Information, 4=Hint
- デバウンス処理により、高頻度の編集時でも過剰な通知送信を防止

---

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

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

### 推奨読解順序

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

診断情報のデータ構造を理解することが重要です。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | kondo-finding->diagnostic関数（36-64行目）で診断マップ構造を確認 |
| 1-2 | diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | diagnostic-types-of-unnecessary-type（14-25行目）でタグ付け対象タイプを確認 |

**読解のコツ**: `:range`、`:severity`、`:code`、`:message`、`:source`、`:tags`が主要フィールドです。

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

通知送信のエントリーポイントを確認します。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | server.clj | `cli/src/clojure_lsp/server.clj` | ClojureLspProducerのpublish-diagnostic（131-137行目）で送信処理を確認 |
| 2-2 | server.clj | `cli/src/clojure_lsp/server.clj` | spawn-async-tasks!（597-622行目）でデバウンス処理を確認 |

**主要処理フロー**:
1. **600行目**: shared/debounce-byでURIごとに25msデバウンス
2. **607-610行目**: spawn-async-loopで診断チャンネルからメッセージ取得・送信
3. **131-137行目**: publish-diagnosticでLSP通知送信

#### Step 3: 診断収集層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | find-diagnostics関数（115-129行目）で診断統合ロジックを確認 |
| 3-2 | diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | publish-diagnostics!関数（145-146行目）で公開処理を確認 |

**主要処理フロー**:
- **115-129行目**: kondo/depend/built-in/customの各診断を収集・統合
- **145-146行目**: diagnostics-of-uri経由でチャンネルに送信

#### Step 4: 診断トリガーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | file_management.clj | `lib/src/clojure_lsp/feature/file_management.clj` | did-open関数（40-61行目）でファイルオープン時の診断を確認 |
| 4-2 | file_management.clj | `lib/src/clojure_lsp/feature/file_management.clj` | analyze-changes関数（255-281行目）でファイル変更時の診断を確認 |

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

```
トリガー（didOpen/didChange/didChangeWatchedFiles）
    │
    ├─ f.diagnostic/publish-diagnostics!
    │      │
    │      └─ publish-diagnostic!*
    │             │
    │             └─ async/>!! diagnostics-chan
    │
    └─ spawn-async-loop! :diagnostics
           │
           ├─ shared/debounce-by (25ms)
           │
           └─ producer/publish-diagnostic
                  │
                  ├─ find-diagnostics
                  │      │
                  │      ├─ kondo-findings->diagnostics
                  │      ├─ clj-depend-violations->diagnostics
                  │      ├─ built-in-diagnostics
                  │      └─ custom-diagnostics->diagnostics
                  │
                  ├─ conform-or-log ::coercer/publish-diagnostics-params
                  │
                  └─ jsonrpc.server/send-notification "textDocument/publishDiagnostics"
```

### データフロー図

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

各種トリガー ──▶ diagnostics-chan ──▶ debounce-by ──▶ find-diagnostics
                                                              │
                                           ┌──────────────────┴──────────────────┐
                                           │                                      │
                                     clj-kondo診断                          統合・フォーマット
                                     clj-depend診断                               │
                                     built-in診断                                 ▼
                                     custom診断                      PublishDiagnosticsParams
                                           │                                      │
                                           └────────────────▶────────────────────┘
                                                                                  │
                                                                                  ▼
                                                              textDocument/publishDiagnostics通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| server.clj | `cli/src/clojure_lsp/server.clj` | ソース | LSP通知送信・デバウンス処理 |
| diagnostics.clj | `lib/src/clojure_lsp/feature/diagnostics.clj` | ソース | 診断収集・変換のコアロジック |
| file_management.clj | `lib/src/clojure_lsp/feature/file_management.clj` | ソース | ファイル操作時の診断トリガー |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | 初期化時の一括診断 |
| producer.clj | `lib/src/clojure_lsp/producer.clj` | ソース | IProducerプロトコル定義 |
| shared.clj | `lib/src/clojure_lsp/shared.clj` | ソース | debounce-by等のユーティリティ |
| kondo.clj | `lib/src/clojure_lsp/kondo.clj` | ソース | clj-kondo統合 |
