# 通知設計書 23-served/doDscanner

## 概要

本ドキュメントは、serve-d LSPサーバーにおけるカスタム通知「served/doDscanner」の設計仕様を定義する。本通知はクライアント(エディタ)からサーバーに送信され、指定ドキュメントに対してD-Scannerによる静的解析（リント）を実行する。

### 本通知の処理概要

本通知は、D-Scannerを使用してD言語ソースファイルの静的解析を手動でトリガーするものである。

**業務上の目的・背景**：D-Scannerはd言語の静的解析ツールで、潜在的なバグやスタイル違反を検出する。通常はtextDocument/didChange通知時に自動的に実行されるが、本通知により任意のタイミングでの手動実行も可能としている。また、deprecated（非推奨）のエイリアス「coded/doDscanner」も同一ハンドラで処理される。

**通知の送信タイミング**：(1) ユーザーがエディタのコマンドパレットから「Run D-Scanner」を実行した場合。(2) textDocument/didChange通知の内部処理として自動的に呼び出される場合。

**通知の受信者**：serve-d LSPサーバープロセスが受信者である。

**通知内容の概要**：DidChangeTextDocumentParams（textDocument.uriを含む）をパラメータとして受け取る。ただし@nonStandard修飾されているため、パラメータが省略される場合もある。

**期待されるアクション**：サーバーは指定ドキュメントに対してD-Scannerリントを実行し、結果をtextDocument/publishDiagnostics通知でクライアントに返す。実行にはデバウンスが適用され、大きなファイル（50KB超）では1000ms、それ以外は200msの遅延が設定される。

## 通知種別

LSPカスタム通知（JSON-RPC Notification）。クライアントからサーバーへの方向（C->S）。「coded/doDscanner」はdeprecatedエイリアス。

## 送信仕様

### 基本情報

| 項目 | 内容 |
|-----|------|
| 送信方式 | 非同期（JSON-RPC notification） |
| 優先度 | 中 |
| リトライ | なし |

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

クライアントがserve-d LSPサーバーに直接送信する。サーバー内部では対象ドキュメントのURIに基づいて処理が行われる。

## 通知テンプレート

### メール通知の場合

該当なし。本通知はLSPプロトコル上のJSON-RPCメッセージである。

### 本文テンプレート

```json
{
  "jsonrpc": "2.0",
  "method": "served/doDscanner",
  "params": {
    "textDocument": {
      "uri": "file:///path/to/file.d"
    }
  }
}
```

### 添付ファイル

該当なし。

## テンプレート変数

| 変数名 | 説明 | データ取得元 | 必須 |
|--------|------|-------------|-----|
| textDocument.uri | 解析対象のドキュメントURI | クライアントのアクティブエディタ | Yes |

## 送信トリガー・条件

### トリガー一覧

| トリガー種別 | トリガーイベント | 送信条件 | 説明 |
|------------|----------------|---------|------|
| 画面操作 | ユーザーが「Run D-Scanner」コマンドを実行 | なし | 手動リント実行 |
| 内部呼び出し | textDocument/didChange処理内 | 対象がD言語ファイル | onDidChangeDocumentからdoDscanner呼び出し |

### 送信抑止条件

| 条件 | 説明 |
|-----|------|
| D言語以外のファイル | document.getLanguageId != "d" の場合はスキップ |
| 静的リント無効 | config.d.enableStaticLinting == false の場合はスキップ |
| リント無効 | config.d.enableLinting == false の場合はスキップ |

## 処理フロー

### 送信フロー

```mermaid
flowchart TD
    A[served/doDscanner通知受信] --> B{D言語ファイル?}
    B -->|No| C[処理終了]
    B -->|Yes| D{静的リント有効?}
    D -->|No| C
    D -->|Yes| E[デバウンスタイマー設定]
    E --> F[タイマー経過後]
    F --> G[D-Scannerリント実行]
    G --> H[textDocument/publishDiagnostics送信]
    H --> I[終了]
```

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

### 参照テーブル一覧

該当なし。

### 更新テーブル一覧

該当なし。

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 対処方法 |
|----------|---------|---------|
| ドキュメント未発見 | 指定URIに対応するドキュメントがない | 処理をスキップ |
| D-Scanner実行失敗 | DscannerComponentが利用不可 | エラーログ出力 |

### リトライ仕様

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

## 配信設定

### レート制限

| 項目 | 内容 |
|-----|------|
| デバウンス | ファイルサイズ50KB超: 1000ms、以下: 200ms |
| 同時実行 | clearTimeoutにより前回タイマーがキャンセルされる |

### 配信時間帯

制限なし。

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

ローカルファイルシステム上のソースコードに対する静的解析のみであり、外部通信は発生しない。

## 備考

- 「coded/doDscanner」は非推奨（deprecated）のエイリアスであり、同一ハンドラで処理される
- textDocument/didChange処理内からも内部的に呼び出されるため、手動実行と自動実行の両方に対応
- デバウンス処理により短時間の連続変更時にはリントが間引かれる
- dscannerChangeTimeoutグローバル変数でタイマーIDを管理

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protocol.d | `protocol/source/served/lsp/protocol.d` | DidChangeTextDocumentParamsの定義 |

**読解のコツ**: @nonStandard修飾により、パラメータのデシリアライズが柔軟に行われる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | doDscanner関数（L1168-1187）が通知ハンドラ |

**主要処理フロー**:
1. **L1168**: `@protocolNotification("coded/doDscanner")` deprecatedエイリアス
2. **L1169**: `@protocolNotification("served/doDscanner")` メイン登録
3. **L1170**: 関数シグネチャ `void doDscanner(@nonStandard DidChangeTextDocumentParams params)`
4. **L1172-1173**: ドキュメント取得とD言語チェック
5. **L1175-1176**: 設定チェック（enableStaticLinting, enableLinting）
6. **L1179-1186**: デバウンス処理とD-Scannerリント実行

#### Step 3: 自動呼び出し元を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | onDidChangeDocument関数（L1148-1165）からdoDscanner呼び出し |

**主要処理フロー**:
- **L1155**: `doDscanner(params)` 呼び出し（didChange内からの直接呼び出し）

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

```
[クライアント] served/doDscanner通知 (または textDocument/didChange内から)
    |
    +-- RPCProcessor
          |
          +-- doDscanner() [extension.d L1170]
                |
                +-- documents[uri] (ドキュメント取得)
                |
                +-- config().d (設定チェック)
                |
                +-- setTimeout() (デバウンス)
                      |
                      +-- served.linters.dscanner.lint() (D-Scanner実行)
                            |
                            +-- textDocument/publishDiagnostics (結果送信)
```

### データフロー図

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

DidChangeTextDocumentParams --> doDscanner()           --> textDocument/publishDiagnostics
(textDocument.uri)             D-Scannerリント実行        (診断結果)
                               デバウンス付き
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | doDscanner通知ハンドラ（L1168-1187）、onDidChangeDocument（L1148-1165） |
| dscanner.d | `source/served/linters/dscanner.d` | ソース | D-Scannerリント実行ロジック |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断情報の管理・publishDiagnostics送信 |
| protocol.d | `protocol/source/served/lsp/protocol.d` | ソース | DidChangeTextDocumentParams型定義 |
