# 画面設計書 58-依存関係インストール（served/installDependency）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供するカスタム通知 `served/installDependency` の設計を記述する。この通知は、DUBパッケージのレシピファイル（dub.json/dub.sdl）に依存関係を追加し、dub upgradeを実行する。

### 本画面の処理概要

このカスタム通知は、エディタ（LSPクライアント）からの要求に応じて、DUBレシピファイルに新しい依存関係を注入し、不足パッケージのダウンロードとインポートパスの更新を一括で実行する処理である。

**業務上の目的・背景**：D言語の開発において、外部パッケージ（ライブラリ）を利用する場合、DUBレシピファイルに依存関係を追加し、パッケージをダウンロードし、インポートパスを更新する一連の作業が必要である。この通知により、エディタのDUBツリービューから直接依存関係を追加でき、手動でのレシピファイル編集やコマンドライン操作を不要にする。

**画面へのアクセス方法**：LSPクライアントが `served/installDependency` 通知をJSON-RPCで送信する。通常はエディタのDUBツリービューの「パッケージ追加」操作やコマンドパレットから実行される。

**主要な操作・処理内容**：
1. クライアントからJSON-RPC通知 `served/installDependency` を受信する
2. DUBレシピファイル（dub.sdl または dub.json）に依存関係を追加する
3. 不足パッケージの自動ダウンロードを実行する
4. インポートパスを更新する（served/updateImports を内部呼び出し）

**画面遷移**：DUB依存関係管理フローの一部として動作する。依存関係ツリー表示（No.55: served/listDependencies）から操作対象を選択し、インストール後はインポートパス更新（No.54: served/updateImports）が実行され、最終的にDUBツリー更新通知が発生する。

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 58 | 依存関係インストール (served/installDependency) | 主機能 | DUBレシピファイルに依存関係を追加しdub upgradeとインポート更新を実行する |
| 54 | インポート更新 (served/updateImports) | 遷移先機能 | 依存関係インストール後にインポートパスの更新処理を呼び出す |

## 画面種別

カスタムLSP通知（ファイル更新処理）

## URL/ルーティング

LSPカスタム通知: `served/installDependency`

## 入出力項目

### 入力（通知パラメータ）

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| name | string | はい | インストールする依存パッケージの名前（例: "vibe-d"） |
| version | string | はい | インストールするバージョン（例: "0.9.5"） |

### 出力

通知のため直接的な戻り値はなし。処理結果はDUBレシピファイルの更新とインポートパスの更新として反映される。

## 表示項目

進捗通知としてクライアントに送信される情報：

| 項目 | 表示形式 | 説明 |
|------|----------|------|
| importUpgrades進捗 | 数値（0/10） | 処理開始 |
| dubReload進捗 | 数値（7/10） | DUB依存関係リロード完了 |
| dubReload進捗 | 数値（10/10） | 全処理完了 |

## イベント仕様

### 1-通知受信

クライアントから `served/installDependency` 通知を受信すると、以下の処理が実行される：

1. `InstallRequest` からパラメータをデシリアライズする
2. `activeInstance` を取得する
3. `importUpgrades` 進捗（0/10）を通知する
4. `injectDependency` 関数を呼び出してレシピファイルに依存関係を追加する
5. DubComponentが存在する場合、`selectAndDownloadMissing()` で不足パッケージをダウンロードする
6. `dubReload` 進捗（7/10）を通知する
7. `updateImports(UpdateImportsParams(false))` でインポートパスを更新する（進捗通知なし）
8. `dubReload` 進捗（10/10）を通知する

### 2-injectDependency（dub.sdl の場合）

1. `dub.sdl` ファイルの存在を確認する
2. ファイル内容を行単位で読み込む
3. 改行コードを検出する（\r\n または \n）
4. トップレベル（depth=0）の最後の `dependency` 行の直後を挿入位置とする
5. `dependency "{name}" version="~>{version}"` の行をファイルに挿入する

### 3-injectDependency（dub.json / package.json の場合）

1. `dub.json` またはフォールバックとして `package.json` の存在を確認する
2. ファイル内容を行単位で読み込む
3. `"dependencies":` ブロックが存在する場合：
   - ブロック内に `"{name}": "~>{version}"` を追加する
4. `"dependencies":` ブロックが存在しない場合：
   - ファイル末尾にdependenciesブロックを新規追加する
5. ファイルが空の場合：
   - 完全なJSON構造体を新規作成する

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 依存関係注入 | ファイルシステム（dub.sdl/dub.json） | UPDATE | レシピファイルに依存関係行を追加 |
| パッケージダウンロード | ファイルシステム（~/.dub/packages） | INSERT | 不足パッケージをダウンロード |
| インポートパス更新 | インメモリ（DCDキャッシュ） | UPDATE | DCDのインポートパスを再構築 |

### テーブル別更新項目詳細

#### DUBレシピファイル（dub.sdl）

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| INSERT | dependency行 | `dependency "{name}" version="~>{version}"` | トップレベルの最後のdependency行の直後に挿入 |

#### DUBレシピファイル（dub.json）

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| INSERT | dependenciesエントリ | `"{name}": "~>{version}"` | dependenciesオブジェクト内に追加 |

## メッセージ仕様

| メッセージID | 種別 | 条件 | メッセージ内容 |
|-------------|------|------|---------------|
| (なし) | - | - | 本通知自体ではユーザー向けエラーメッセージは発生しない |

## 例外処理

| 条件 | 動作 | 返却値 |
|------|------|--------|
| dub.sdl も dub.json も package.json も存在しない | レシピファイル更新をスキップ | (通知のため戻り値なし) |
| DubComponentが存在しない | パッケージダウンロードをスキップ | (通知のため戻り値なし) |

## 備考

- `injectDependency` はバージョン指定に `~>` プレフィックスを付与する（セマンティックバージョニングの互換範囲指定）
- SDL形式の場合は `dependency "name" version="~>ver"` 形式、JSON形式の場合は `"name": "~>ver"` 形式で追加される
- 改行コードはファイルの既存の改行コードを検出して使用する
- `@protocolNotification` で登録されており、レスポンスは返されない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | InstallRequest構造体（99-106行目）のフィールド定義を確認 |

**読解のコツ**: `@serdeKeys("version") string version_` はD言語の予約語回避。JSON上は "version" キーとしてデシリアライズされる。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | dub.d | `source/served/commands/dub.d` | installDependency関数（574-586行目）がエントリーポイント |

**主要処理フロー**:
1. **574行目**: `@protocolNotification("served/installDependency")` UDAで通知ハンドラとして登録
2. **577行目**: `activeInstance` 取得
3. **579行目**: `reportProgress(ProgressType.importUpgrades, 0, 10, uri)` - 進捗開始
4. **580行目**: `injectDependency(instance, req)` - レシピファイルに依存関係注入
5. **582行目**: `instance.get!DubComponent.selectAndDownloadMissing()` - パッケージダウンロード
6. **584行目**: `updateImports(UpdateImportsParams(false))` - インポートパス更新

#### Step 3: injectDependency関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d | `source/served/commands/dub.d` | injectDependency関数（623-725行目）- SDL/JSONそれぞれのファイル編集ロジック |

**主要処理フロー**:
- **625-649行目**: dub.sdl形式の処理 - depth=0の最後のdependency行の直後に挿入
- **651-724行目**: dub.json/package.json形式の処理 - dependenciesブロックの有無で分岐

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

```
LSPクライアント (エディタ DUBツリービュー)
    |
    |  served/installDependency (JSON-RPC notification)
    v
installDependency(InstallRequest) [source/served/commands/dub.d:575]
    |
    +-- reportProgress(importUpgrades, 0/10)
    |
    +-- injectDependency(instance, req) [source/served/commands/dub.d:623]
    |       |
    |       +-- [dub.sdl存在] SDL形式で依存関係行を追加
    |       +-- [dub.json/package.json] JSON形式で依存関係を追加
    |
    +-- DubComponent.selectAndDownloadMissing()
    |
    +-- reportProgress(dubReload, 7/10)
    |
    +-- updateImports(UpdateImportsParams(false)) [source/served/commands/dub.d:213]
    |       +-- DubComponent.update
    |       +-- DCDComponent.refreshImports
    |       +-- backgroundIndex
    |
    +-- reportProgress(dubReload, 10/10)
```

### データフロー図

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

JSON-RPC Notification   --->  installDependency()           --->  ファイル更新
  name: "vibe-d"                |                                  |
  version: "0.9.5"              +-- injectDependency              +-- dub.sdl/dub.json更新
                                |   (レシピファイル編集)             +-- パッケージダウンロード
                                +-- selectAndDownloadMissing      +-- DCDインポートパス更新
                                +-- updateImports                 +-- coded/updateDubTree通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/commands/dub.d` | ソース | installDependency関数（574-586行目）、injectDependency関数（623-725行目） |
| protoext.d | `source/served/lsp/protoext.d` | ソース | InstallRequest構造体定義（99-106行目） |
| progress.d | `source/served/utils/progress.d` | ソース | ProgressType定義、reportProgress関数 |
| types.d | `source/served/types.d` | ソース | activeInstance、backend等のグローバル定義 |
| extension.d | `source/served/extension.d` | ソース | LSP通知ディスパッチ基盤 |
