# 画面設計書 13-DUBツリー更新通知

## 概要

DUB依存関係が更新された際に、クライアントに `coded/updateDubTree` 通知を送信し、エディタ側のDUB依存関係ツリービューの再描画をトリガーする通知画面の設計書である。

### 本画面の処理概要

本画面は、DUBのレシピファイル（dub.json / dub.sdl）の保存やインポートパスの更新が行われた際に、クライアントへ `coded/updateDubTree` 通知を送信する処理を担当する。これにより、エディタ側のDUB依存関係ツリービューが最新の状態に更新される。

**業務上の目的・背景**：開発者がdub.jsonやdub.sdlを編集・保存した場合、依存関係の追加・削除・バージョン変更が発生する。エディタ側のツリービューをリアルタイムに最新の依存関係状態に同期させることで、開発者が常に正確なプロジェクト構造を把握できるようにする。

**画面へのアクセス方法**：本通知は以下の操作により自動的にトリガーされる：
- dub.json または dub.sdl ファイルの保存（textDocument/didSave）
- served/updateImports 実行時のDUB更新成功

**主要な操作・処理内容**：
1. DUBレシピファイル（dub.json/dub.sdl）が保存される
2. onDidSaveDubRecipe関数でDUB依存関係の更新処理が実行される
3. 更新完了後に `coded/updateDubTree` 通知をクライアントに送信する
4. updateImports関数でDUB更新が成功した場合にも同通知を送信する

**画面遷移**：ファイル保存（textDocument/didSave）が起点。通知後、クライアントは `served/listDependencies`（No.55）を呼び出して最新の依存関係一覧を取得する。

**権限による表示制御**：権限による表示制御は存在しない。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | ドキュメント保存 (textDocument/didSave) | 補助機能 | ファイル保存時にDUBレシピの変更を検出しDUBツリー更新通知を送信する |
| 55 | 依存関係一覧取得 (served/listDependencies) | 遷移先機能 | DUBツリー更新後にクライアントがcoded/updateDubTree通知を受け取り依存関係一覧を再取得する |

## 画面種別

通知（カスタム通知）

## URL/ルーティング

LSPカスタム通知: `coded/updateDubTree`（サーバーからクライアントへの通知、パラメータなし）

トリガー元:
- `textDocument/didSave`（dub.json/dub.sdlの保存時）
- `served/updateImports`（DUB更新成功時）

## 入出力項目

| 項目名 | 型 | 入力/出力 | 説明 |
|--------|-----|----------|------|
| textDocument | DidSaveTextDocumentParams | 入力 | 保存されたドキュメント情報（dub.json/dub.sdlの場合のみ処理） |
| （なし） | void | 出力 | パラメータなしの通知メソッド |

## 表示項目

| 項目名 | 表示形式 | 説明 |
|--------|----------|------|
| DUB依存関係ツリー | ツリービュー | クライアント側で通知受信後に再描画されるDUB依存関係ツリー |

## イベント仕様

### 1-DUBレシピファイル保存時の通知

dub.jsonまたはdub.sdlが保存された場合の処理フロー:

1. onDidSaveDubRecipe関数がtextDocument/didSave通知を処理
2. ファイル名がdub.json/dub.sdlか判定
3. DubComponentの更新処理を実行（依存関係のダウンロード・インポートパス更新）
4. 324行目で `rpc.notifyMethod("coded/updateDubTree")` を送信

### 2-インポート更新時の通知

served/updateImportsが実行された場合:

1. DubComponentのupdate呼び出しが成功した場合
2. 224行目で `rpc.notifyMethod("coded/updateDubTree")` を送信

## データベース更新仕様

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | なし | なし | データベースアクセスなし |

## メッセージ仕様

| メッセージID | 種別 | メッセージ内容 | 条件 |
|-------------|------|---------------|------|
| なし | 通知 | coded/updateDubTree（パラメータなし） | DUBレシピ保存時またはインポート更新成功時 |

## 例外処理

| 例外条件 | 処理内容 |
|----------|----------|
| DUBレシピのシンタックスエラー | エラーメッセージを表示し、updateDubTree通知は送信されない（onDidSaveDubRecipe内でearly return） |
| DUBコンポーネントが未初期化 | アタッチを試行し、失敗した場合はエラー表示して通知送信をスキップ |
| DUBコンポーネントが実行中でない | エラーメッセージを表示し通知送信をスキップ |

## 備考

- coded/updateDubTreeはserve-d独自のカスタムLSP通知であり、標準LSPプロトコルには含まれない
- onDidSaveDubRecipeでは324行目で即座に通知を送信しているが、インポートパスの更新は200ms後のsetTimeout内で非同期に行われる
- DUBレシピファイル以外の保存では本通知はトリガーされない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | UpdateImportsParams構造体を確認 |

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dub.d | `source/served/commands/dub.d` | onDidSaveDubRecipe関数（234-325行目）がDUBレシピ保存時のエントリーポイント |
| 2-2 | dub.d | `source/served/commands/dub.d` | updateImports関数（212-232行目）がインポート更新時のエントリーポイント |

**主要処理フロー（onDidSaveDubRecipe）**:
1. **237行目**: ファイル名がdub.json/dub.sdlか判定
2. **246-256行目**: DubComponentの存在チェックとアタッチ試行
3. **260-285行目**: DUBの更新処理（validateRecipeSyntax, updateImportPaths, selectAndDownloadMissing）
4. **324行目**: `rpc.notifyMethod("coded/updateDubTree")` 通知送信

**主要処理フロー（updateImports）**:
1. **222行目**: DubComponent.update実行
2. **224行目**: 成功時に `rpc.notifyMethod("coded/updateDubTree")` 通知送信

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

```
textDocument/didSave
    |
    +-- onDidSaveDubRecipe() [dub.d:234]
            |
            +-- DubComponent.updateImportPaths() [dub.d:276]
            +-- DubComponent.selectAndDownloadMissing() [dub.d:277]
            +-- rpc.notifyMethod("coded/updateDubTree") [dub.d:324]
            +-- setTimeout(200ms)
                    +-- updateImports() [dub.d:212]
                            +-- rpc.notifyMethod("coded/updateDubTree") [dub.d:224]

served/updateImports
    |
    +-- updateImports() [dub.d:212]
            +-- DubComponent.update() [dub.d:222]
            +-- rpc.notifyMethod("coded/updateDubTree") [dub.d:224]
```

### データフロー図

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

dub.json/dub.sdl       +-- onDidSaveDubRecipe           +-- coded/updateDubTree通知
（ファイル保存）             |                                  （クライアントへ）
                             +-- DUB依存関係更新
                             +-- インポートパス更新

served/updateImports   +-- updateImports                +-- coded/updateDubTree通知
（手動実行）                 +-- DubComponent.update           （クライアントへ）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/commands/dub.d` | ソース | onDidSaveDubRecipe（234-325行目）、updateImports（212-232行目） |
| extension.d | `source/served/extension.d` | ソース | onDidSaveDocument（1316-1345行目）ドキュメント保存のルーティング |
| types.d | `source/served/types.d` | ソース | rpcグローバル変数の定義 |
