# 機能設計書 39-DScanner手動実行 (served/doDscanner)

## 概要

本ドキュメントは、指定ファイルに対してDScanner静的解析を手動でトリガーするserved/doScannerリクエストの設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：通常のDScanner静的解析はテキスト変更時にデバウンス付きで自動実行されるが、手動で即座に静的解析を実行したい場合がある。本機能は `served/doDscanner` リクエストまたは `coded/doDscanner`（レガシーエイリアス）通知により、指定ファイルに対するDScanner静的解析を手動でトリガーする。

**機能の利用シーン**：クライアントが明示的にDScanner静的解析を実行したい場合に使用する。例えば、ファイルの変更検知が遅れた場合や、特定のタイミングでリント結果を更新したい場合など。自動実行と同じ処理を即座に実行する。

**主要な処理内容**：
1. パラメータからテキストドキュメントを特定する
2. 言語がD言語であることを確認する
3. 設定でD-Scanner静的解析が有効か確認する
4. デバウンスタイマーをリセットし、setTimeoutで遅延実行する
5. 遅延後に `served.linters.dscanner.lint(document)` を呼び出す

**関連システム・外部連携**：No.35「DScanner静的解析」の lint 関数を内部的に呼び出す。デバウンス制御はextension.dのdscannerChangeTimeoutで管理される。

**権限による制御**：設定項目 `d.enableLinting`（デフォルトtrue）と `d.enableStaticLinting`（デフォルトtrue）の両方がtrueの場合のみ実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 34 | DScanner リント（served/doDscanner） | 補助機能 | served/doScannerリクエストによる手動トリガーでDScanner静的解析を実行 |

## 機能種別

静的解析トリガー処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| params.textDocument | VersionedTextDocumentIdentifier | Yes | 対象ドキュメントの識別子（URI, バージョン） | ドキュメントが管理下に存在すること |

### 入力データソース

LSPクライアントからの `served/doDscanner` または `coded/doDscanner`（レガシー）通知。パラメータはDidChangeTextDocumentParams型で受け取る（@nonStandardアノテーション付き）。

## 出力仕様

### 出力データ

本リクエスト自体は直接の応答を返さない（通知ハンドラ）。DScanner解析の結果は `textDocument/publishDiagnostics` 通知として診断マネージャ経由でクライアントに送信される。

### 出力先

診断マネージャ経由の `textDocument/publishDiagnostics` 通知（No.35 DScanner静的解析を参照）。

## 処理フロー

### 処理シーケンス

```
1. ドキュメント取得
   └─ documents[params.textDocument.uri]でドキュメント取得
2. 言語チェック
   └─ document.getLanguageId != "d" の場合は処理終了
3. 設定チェック
   └─ config.d.enableStaticLinting && config.d.enableLinting の両方がtrueか確認
   └─ falseの場合は処理終了
4. デバウンス遅延計算
   └─ ファイルサイズ > 50KB の場合: 1000ms
   └─ ファイルサイズ <= 50KB の場合: 200ms
5. タイマーリセット・設定
   └─ clearTimeout(dscannerChangeTimeout) で既存タイマーをキャンセル
   └─ setTimeout で新しいタイマーを設定
6. 遅延後の解析実行
   └─ served.linters.dscanner.lint(document) を呼び出し
   └─ （以降はNo.35 DScanner静的解析と同じ処理フロー）
```

### フローチャート

```mermaid
flowchart TD
    A["served/doDscanner 通知受信"] --> B[ドキュメント取得]
    B --> C{言語がD?}
    C -->|No| Z[処理終了]
    C -->|Yes| D{静的解析有効?}
    D -->|No| Z
    D -->|Yes| E[デバウンス遅延計算]
    E --> F[既存タイマーキャンセル]
    F --> G[新タイマー設定]
    G --> H["遅延後: dscanner.lint(document)"]
    H --> I["textDocument/publishDiagnostics送信"]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | D言語限定 | D言語ファイルのみ解析対象 | 常時 |
| BR-39-02 | 設定依存 | enableLintingとenableStaticLintingの両方がtrueの場合のみ実行 | 常時 |
| BR-39-03 | デバウンス | ファイルサイズに応じた遅延（200ms/1000ms）でデバウンス実行 | 常時 |
| BR-39-04 | レガシーエイリアス | "coded/doDscanner" でも呼び出し可能（後方互換性） | 常時 |

### 計算ロジック

- デバウンス遅延: `document.length > 50 * 1024 ? 1000 : 200` （ミリ秒）

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

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

本機能にデータベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 非D言語ファイル | ドキュメントの言語IDが "d" でない | 処理終了 |
| - | 設定無効 | enableStaticLintingまたはenableLintingがfalse | 処理終了 |

### リトライ仕様

デバウンスにより、短時間に複数回呼び出された場合は最後の呼び出しのみが実行される。

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

トランザクション管理は不要。

## パフォーマンス要件

デバウンス制御により、大量のリクエストが短時間に発生してもサーバーに過負荷がかからないよう制御されている。

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

特になし。

## 備考

- `@nonStandard` アノテーションにより、DidChangeTextDocumentParams型の直接的なデシリアライゼーションではなく、柔軟なパラメータ処理が行われる。
- onDidChangeDocument（textDocument/didChange）からも間接的にこの関数が呼ばれる（extension.d 1155行目）。
- dscannerChangeTimeoutはモジュールレベル変数として管理され、複数の呼び出し元で共有される。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | extension.d | `source/served/extension.d` | dscannerChangeTimeoutモジュール変数（1167行目）を確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | extension.d | `source/served/extension.d` | `doDscanner` 関数（1168-1187行目）がserved/doScannerリクエストハンドラ |

**主要処理フロー**:
1. **1168-1169行目**: `@protocolNotification("coded/doDscanner")` と `@protocolNotification("served/doDscanner")` の二重登録
2. **1170行目**: `@nonStandard` アノテーション
3. **1172-1173行目**: ドキュメント取得・言語チェック
4. **1175-1177行目**: 設定チェック
5. **1179行目**: デバウンス遅延計算（50KB閾値）
6. **1180行目**: `clearTimeout(dscannerChangeTimeout)` でタイマーリセット
7. **1181-1186行目**: `setTimeout` で遅延実行設定、内部で `dscanner.lint(document)` 呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | extension.d | `source/served/extension.d` | `onDidChangeDocument`（1148-1165行目）が1155行目で `doDscanner(params)` を呼び出す |

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

```
served/doDscanner 通知 → doDscanner (extension.d:1170)
coded/doDscanner 通知 → doDscanner (extension.d:1170)  [レガシー]
onDidChangeDocument → doDscanner (extension.d:1155)     [自動]
    |
    +-- documents[uri] (ドキュメント取得)
    +-- document.getLanguageId (言語チェック)
    +-- config().d.enableStaticLinting チェック
    +-- clearTimeout(dscannerChangeTimeout)
    +-- setTimeout (デバウンス)
            └─ served.linters.dscanner.lint(document)
                   └─ (No.35 DScanner静的解析の処理フロー)
```

### データフロー図

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

DidChangeTextDocumentParams  ──▶  doDscanner()               ──▶  textDocument/publishDiagnostics
  .textDocument.uri                |                                 (No.35経由)
                                   +-- デバウンス制御
                                   +-- setTimeout
                                   +-- dscanner.lint(document)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| extension.d | `source/served/extension.d` | ソース | doDscanner関数（手動トリガーハンドラ） |
| dscanner.d | `source/served/linters/dscanner.d` | ソース | lint関数（実際の解析処理）- No.35参照 |
| diagnosticmanager.d | `source/served/linters/diagnosticmanager.d` | ソース | 診断結果の配信 |
| types.d | `source/served/types.d` | ソース | 設定項目定義 |
