# 機能設計書 59-依存関係更新

## 概要

本ドキュメントは、serve-dのLSPカスタム通知 `served/updateDependency` の機能設計を記述する。DUBレシピファイル内の依存関係バージョンを更新し、dub upgradeとインポート更新を実行する機能である。

### 本機能の処理概要

**業務上の目的・背景**：D言語のDUBプロジェクトでは、依存パッケージのバージョンを定期的に更新する必要がある。本機能は、エディタ上から既存の依存関係のバージョンを変更する操作を自動化する。dub.sdlまたはdub.json形式のレシピファイル内のバージョン文字列を正規表現で検索・置換し、パッケージのダウンロードとインポートパスの更新を一連の処理として実行する。

**機能の利用シーン**：エディタの依存関係管理UIから既存パッケージのバージョンを更新する際に使用される。

**主要な処理内容**：
1. クライアントから `served/updateDependency` 通知を受信する
2. 進捗レポートを開始する
3. `changeDependency` 関数でDUBレシピファイルのバージョン文字列を更新する
4. 更新成功時、DubComponentの `selectAndDownloadMissing()` で不足パッケージをダウンロードする
5. `updateImports()` でインポートパスを更新する
6. 進捗レポートを完了する

**関連システム・外部連携**：ファイルシステム上のDUBレシピファイル（dub.sdl/dub.json）を直接編集する。DubComponentを通じてパッケージダウンロードを実行する。updateImports（No.54）を内部呼出しする。

**権限による制御**：特に権限による制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 59 | 依存関係更新（served/updateDependency） | 主画面 | DUBレシピファイル内の依存関係バージョンを更新する |

## 機能種別

ファイル編集・状態更新処理（DUBレシピファイルのバージョン更新、パッケージダウンロード、インポート更新）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | 更新対象のDUB依存関係パッケージ名 | なし |
| version | string | Yes | 新しいバージョン文字列 | なし |

### 入力データソース

LSPクライアントからのJSON-RPC通知（UpdateRequest構造体）

## 出力仕様

### 出力データ

本機能は通知（Notification）であるため、直接の戻り値はない。以下の副作用を生じる。

| 項目名 | 型 | 説明 |
|--------|-----|------|
| レシピファイル編集 | ファイルシステム | dub.sdlまたはdub.json内のバージョン文字列を更新 |
| パッケージダウンロード | ファイルシステム | 不足パッケージをDUBのローカルキャッシュにダウンロード |
| インポートパス更新 | インメモリ | DCDとインデックスのインポートパスを更新 |

### 出力先

- ファイルシステム上のDUBレシピファイル
- 進捗通知によるUI更新

## 処理フロー

### 処理シーケンス

```
1. 通知受信
   └─ UpdateRequestとしてデシリアライズ
2. 進捗レポート開始
   └─ ProgressType.importUpgrades (0/10)
3. 依存関係バージョン変更
   └─ changeDependency() でレシピファイルのバージョン文字列を更新
       ├─ [dub.sdlの場合] 対象dependency行のversion部分をインデックス操作で置換
       └─ [dub.jsonの場合] 正規表現で対象パッケージのバージョン文字列を置換
4. 変更成功時の処理
   ├─ DubComponent.selectAndDownloadMissing() で不足パッケージをダウンロード
   ├─ 進捗レポート中間 (7/10)
   └─ updateImports(UpdateImportsParams(false)) でインポートパス更新
5. 進捗レポート完了
   └─ ProgressType.dubReload (10/10)
```

### フローチャート

```mermaid
flowchart TD
    A[served/updateDependency 通知受信] --> B[進捗レポート開始 0/10]
    B --> C[changeDependency でバージョン更新]
    C --> D{更新成功?}
    D -->|Yes| E{DubComponent あり?}
    D -->|No| F[進捗レポート完了 10/10]
    E -->|Yes| G[selectAndDownloadMissing]
    E -->|No| H[進捗レポート 7/10]
    G --> H
    H --> I[updateImports 呼出]
    I --> F
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-59-01 | SDL/JSON自動判定 | dub.sdlが存在する場合はSDL形式、そうでない場合はdub.json/package.jsonを使用する | 常時 |
| BR-59-02 | SDLバージョン置換 | SDL形式では、対象パッケージのdependency行を見つけ、version="..."部分の文字列をインデックス操作で置換する | dub.sdl使用時 |
| BR-59-03 | JSONバージョン置換 | JSON形式では、`"name" : "version"` パターンを正規表現で検索し、バージョン文字列を置換する | dub.json使用時 |
| BR-59-04 | 条件付き後続処理 | changeDependencyが成功（true返却）した場合のみ、パッケージダウンロードとインポート更新を実行する | 変更成功時 |
| BR-59-05 | depth追跡（SDL） | `{` と `}` の出現数でdepthを追跡し、トップレベルのdependency行のみを対象とする | dub.sdl使用時 |

### 計算ロジック

特になし。

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

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

本機能はデータベースを使用しない。ファイルシステム上のDUBレシピファイルを直接編集する。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 暗黙的失敗（false） | dub.sdl/dub.jsonが存在しない場合 | changeDependencyがfalseを返却し、後続処理をスキップ |
| - | 暗黙的失敗（false） | 対象パッケージ名がレシピファイルに見つからない場合 | changeDependencyがfalseを返却 |
| - | 暗黙的失敗（false） | SDLのversion部分が見つからない場合 | changeDependencyがfalseを返却 |

### リトライ仕様

リトライは不要。

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

トランザクション管理は不要。レシピファイルの書き込みはアトミックではない。

## パフォーマンス要件

レシピファイルの編集はファイルシステムI/Oを伴う。selectAndDownloadMissingはネットワーク通信を伴う可能性がある。

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

正規表現を使用したファイル編集を行うため、パッケージ名にメタ文字が含まれる場合はインジェクションのリスクがある。ただし、DUBのパッケージ名の命名規則により、通常はメタ文字は含まれない。

## 備考

- コードにTODOコメント（591行目）があり、dub.selections.jsonの更新が未実装である
- SDL形式のバージョン置換はインデックス操作（indexOf）で実装されているのに対し、JSON形式は正規表現（replaceFirst）で実装されている
- changeDependencyは成否をboolで返却し、失敗時は後続のパッケージダウンロードとインポート更新がスキップされる

---

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

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

### 推奨読解順序

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

UpdateRequest構造体のフィールドを確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | protoext.d | `source/served/lsp/protoext.d` | UpdateRequest構造体（109-116行目）のnameとversion_フィールドを確認 |

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

updateDependency関数の全体処理を把握する。

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

**主要処理フロー**:
1. **588行目**: `@protocolNotification("served/updateDependency")` - LSP通知として登録
2. **591行目**: `// TODO: update in dub.selections.json` - 未実装のTODO
3. **595行目**: `reportProgress(ProgressType.importUpgrades, 0, 10, uri)` - 進捗開始
4. **596行目**: `changeDependency(instance, req)` - バージョン変更実行（成否がif条件）
5. **598-601行目**: 成功時のみselectAndDownloadMissingとupdateImportsを実行
6. **603行目**: `reportProgress(ProgressType.dubReload, 10, 10, uri)` - 進捗完了

#### Step 3: バージョン変更処理を理解する

changeDependency関数のSDL/JSON各形式での置換ロジックを把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | dub.d | `source/served/commands/dub.d` | changeDependency関数（727-776行目） |

**主要処理フロー**:
- **729-760行目**: SDL形式の処理。depth追跡でトップレベルの対象パッケージ行を探し、version="..."部分をindexOfで特定して置換
- **761-776行目**: JSON形式の処理。正規表現 `("name"\s*:\s*)"[^"]*"` で対象パッケージのバージョン文字列を置換

**読解のコツ**: SDL形式のバージョン置換は手動のインデックス操作で行われている。`indexOf("version", ver)` でversionキーワードを見つけ、その後の最初のダブルクォート間の文字列を新バージョンに置き換える。

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

```
updateDependency(UpdateRequest) [source/served/commands/dub.d:589]
    |
    +-- activeInstance [source/served/types.d:471]
    |
    +-- reportProgress(...) [source/served/utils/progress.d:53]
    |
    +-- changeDependency(instance, req) [source/served/commands/dub.d:727]
    |       |
    |       +-- fs.exists(sdl) / fs.exists(json) [ファイル存在確認]
    |       +-- fs.readText / splitLines [ファイル読込]
    |       +-- indexOf / replaceFirst(regex(...)) [バージョン文字列置換]
    |       +-- fs.write [ファイル書き込み]
    |
    +-- [成功時のみ]
    |   +-- DubComponent.selectAndDownloadMissing() [workspace-d API]
    |   +-- updateImports(UpdateImportsParams(false)) [source/served/commands/dub.d:213]
    |
    +-- reportProgress(完了)
```

### データフロー図

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

UpdateRequest              -->  updateDependency()                 -->  レシピファイル編集
  name: string                   |                                       パッケージDL（成功時）
  version: string                +-- changeDependency (バージョン置換)   インポートパス更新（成功時）
                                 +-- [成功時] selectAndDownloadMissing   進捗通知
                                 +-- [成功時] updateImports
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/commands/dub.d` | ソース | updateDependency（588-604行目）、changeDependency（727-776行目） |
| protoext.d | `source/served/lsp/protoext.d` | ソース | UpdateRequest構造体定義（109-116行目） |
| progress.d | `source/served/utils/progress.d` | ソース | reportProgress関数 |
| types.d | `source/served/types.d` | ソース | activeInstanceプロパティ、backend定義 |
| index.d | `source/served/commands/index.d` | ソース | backgroundIndex関数（updateImports経由で呼出） |
