# 画面設計書 60-依存関係削除（served/uninstallDependency）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供するカスタム通知 `served/uninstallDependency` の設計を記述する。この通知は、DUBレシピファイルから指定された依存関係を削除し、dub upgradeとインポートパス更新を実行する。

### 本画面の処理概要

このカスタム通知は、エディタ（LSPクライアント）からの要求に応じて、DUBレシピファイル（dub.sdl/dub.json）から指定された依存関係を削除し、パッケージ情報の再同期とインポートパスの更新を行う処理である。

**業務上の目的・背景**：D言語の開発において、不要になったパッケージ依存関係を除去することは、ビルド時間の短縮やプロジェクトの整理において重要である。手動でのレシピファイル編集は、特にJSON形式で末尾カンマの処理やSDL形式の構文に注意が必要であり、エラーが発生しやすい。この通知により、エディタのDUBツリービューから直接依存関係を削除でき、レシピファイルの構文を壊さずに安全にエントリを除去する。

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

**主要な操作・処理内容**：
1. クライアントからJSON-RPC通知 `served/uninstallDependency` を受信する
2. `removeDependency` 関数でレシピファイルから依存関係エントリを削除する
3. 不足パッケージの同期処理を実行する
4. インポートパスを更新する（served/updateImports を内部呼び出し）

**画面遷移**：DUB依存関係管理フローの一部として動作する。依存関係ツリー表示（No.55）で対象パッケージを選択し、削除後はインポートパス更新（No.54）が実行され、DUBツリー更新通知が発生する。

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

## 関連機能

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

## 画面種別

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

## URL/ルーティング

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

## 入出力項目

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

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| name | string | はい | 削除する依存パッケージの名前（例: "vibe-d"） |

### 出力

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

## 表示項目

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

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

## イベント仕様

### 1-通知受信

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

1. `UninstallRequest` からパラメータをデシリアライズする
2. `activeInstance` を取得する
3. `importUpgrades` 進捗（0/10）を通知する
4. `removeDependency(instance, req.name)` 関数を呼び出して依存関係を削除する
5. DubComponentが存在する場合、`selectAndDownloadMissing()` でパッケージ情報を同期する
6. `dubReload` 進捗（7/10）を通知する
7. `updateImports(UpdateImportsParams(false))` でインポートパスを更新する（進捗通知なし）
8. `dubReload` 進捗（10/10）を通知する

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

1. `dub.sdl` ファイルの存在を確認する
2. ファイル内容を行単位で読み込む
3. トップレベル（depth=0）で `dependency "{name}"` で始まる行を検索する
4. 対象行が見つかった場合、その行を配列から除去する
5. 対象行が見つからない場合はfalseを返す
6. 行を除去した配列をファイルに書き戻す

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

1. `dub.json` またはフォールバックとして `package.json` の存在を確認する
2. ファイル内容全体を読み込む
3. 以下の4つの正規表現パターンを順に試行して依存関係エントリを削除する：
   - パターン1: `"{name}"\s*:\s*"[^"]*"\s*,\s*` - エントリ + 後続カンマ
   - パターン2: `\s*,\s*"{name}"\s*:\s*"[^"]*"` - 先行カンマ + エントリ
   - パターン3: `"dependencies"\s*:\s*\{\s*"{name}"\s*:\s*"[^"]*"\s*\}\s*,\s*` - 唯一の依存関係のdependenciesブロック + 後続カンマ
   - パターン4: `\s*,\s*"dependencies"\s*:\s*\{\s*"{name}"\s*:\s*"[^"]*"\s*\}` - 先行カンマ + 唯一の依存関係のdependenciesブロック
4. いずれのパターンでも置換が発生しなかった場合はfalseを返す
5. ファイルに書き戻す

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| 依存関係削除 | ファイルシステム（dub.sdl/dub.json） | DELETE相当 | レシピファイルから依存関係エントリを除去 |
| パッケージ同期 | インメモリ | UPDATE | DubComponentのパッケージ情報を再同期 |
| インポートパス更新 | インメモリ（DCDキャッシュ） | UPDATE | DCDのインポートパスを再構築 |

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

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

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| DELETE | dependency行 | (行ごと削除) | 該当するdependency行を配列から除去 |

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

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| DELETE | dependenciesエントリ | (正規表現で除去) | カンマ処理を含む4パターンの正規表現で安全に除去 |

## メッセージ仕様

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

## 例外処理

| 条件 | 動作 | 返却値 |
|------|------|--------|
| dub.sdl も dub.json も package.json も存在しない | removeDependencyがfalseを返す | (通知のため戻り値なし) |
| 指定された依存関係がレシピファイルに見つからない | removeDependencyがfalseを返す | (通知のため戻り値なし) |
| DubComponentが存在しない | パッケージ同期をスキップ | (通知のため戻り値なし) |

## 備考

- ソースコード内に `// TODO: remove from dub.selections.json` および `// TODO: add workspace argument` コメントがあり、これらは未実装
- removeDependencyの結果（true/false）に関わらず、パッケージ同期とインポートパス更新は常に実行される（installDependencyと同じ動作だが、updateDependencyとは異なる）
- JSON形式の削除は4つの正規表現パターンで末尾カンマ・先頭カンマの処理を安全に行う
- SDL形式の削除は単純な行削除で行われる
- `@protocolNotification` で登録されており、レスポンスは返されない

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | UninstallRequest構造体（119-123行目）のフィールド定義を確認。nameフィールドのみ（versionフィールドなし） |

**読解のコツ**: UninstallRequestはInstallRequest/UpdateRequestと異なり、nameフィールドのみを持つ。バージョン指定は不要（該当パッケージ全体を削除するため）。

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

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

**主要処理フロー**:
1. **606行目**: `@protocolNotification("served/uninstallDependency")` UDAで通知ハンドラとして登録
2. **609行目**: TODOコメント - dub.selections.jsonからの削除は未実装
3. **613行目**: `reportProgress(ProgressType.importUpgrades, 0, 10, uri)` - 進捗開始
4. **615行目**: `removeDependency(instance, req.name)` - 依存関係削除実行
5. **617行目**: `instance.get!DubComponent.selectAndDownloadMissing()` - パッケージ同期
6. **619行目**: `updateImports(UpdateImportsParams(false))` - インポートパス更新

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d | `source/served/commands/dub.d` | removeDependency関数（778-823行目）- SDL/JSONそれぞれの依存関係削除ロジック |

**主要処理フロー**:
- **780-799行目**: dub.sdl形式の処理 - dependency行を検索し、配列から行を除去
- **800-823行目**: dub.json形式の処理 - 4つの正規表現パターンで安全に削除
  - **809行目**: パターン1: エントリ + 後続カンマ
  - **811行目**: パターン2: 先行カンマ + エントリ
  - **813行目**: パターン3: dependenciesブロック全体（唯一の依存関係） + 後続カンマ
  - **816行目**: パターン4: 先行カンマ + dependenciesブロック全体（唯一の依存関係）

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

```
LSPクライアント (エディタ DUBツリービュー)
    |
    |  served/uninstallDependency (JSON-RPC notification)
    v
uninstallDependency(UninstallRequest) [source/served/commands/dub.d:607]
    |
    +-- reportProgress(importUpgrades, 0/10)
    |
    +-- removeDependency(instance, req.name) [source/served/commands/dub.d:778]
    |       |
    |       +-- [dub.sdl存在] SDL形式でdependency行を削除
    |       |       +-- depth=0のdependency "{name}"行を検索
    |       |       +-- 該当行を配列から除去
    |       |
    |       +-- [dub.json/package.json] JSON形式で正規表現により削除
    |               +-- パターン1: エントリ + 後続カンマ
    |               +-- パターン2: 先行カンマ + エントリ
    |               +-- パターン3: 唯一の依存関係ブロック + 後続カンマ
    |               +-- パターン4: 先行カンマ + 唯一の依存関係ブロック
    |
    +-- 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   --->  uninstallDependency()         --->  ファイル更新
  name: "vibe-d"                |                                  |
                                +-- removeDependency              +-- dub.sdl/dub.json更新
                                |   (依存関係エントリ削除)           |   (該当行/エントリ除去)
                                +-- selectAndDownloadMissing      +-- DCDインポートパス更新
                                +-- updateImports                 +-- coded/updateDubTree通知
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/commands/dub.d` | ソース | uninstallDependency関数（606-621行目）、removeDependency関数（778-823行目） |
| protoext.d | `source/served/lsp/protoext.d` | ソース | UninstallRequest構造体定義（119-123行目） |
| progress.d | `source/served/utils/progress.d` | ソース | ProgressType定義、reportProgress関数 |
| types.d | `source/served/types.d` | ソース | activeInstance、backend等のグローバル定義 |
| extension.d | `source/served/extension.d` | ソース | LSP通知ディスパッチ基盤 |
