# 画面設計書 57-DUBフォーマット変換（served/convertDubFormat）

## 概要

本ドキュメントは、serve-d LSPサーバーが提供するカスタム通知 `served/convertDubFormat` の設計を記述する。この通知は、dub.json と dub.sdl のフォーマットを相互変換する処理を実行する。

### 本画面の処理概要

このカスタム通知は、エディタ（LSPクライアント）からの要求に応じて、DUBレシピファイル（dub.json/dub.sdl）を別のフォーマットに変換する処理である。変換結果は `workspace/applyEdit` によりエディタに適用される。

**業務上の目的・背景**：DUBパッケージマネージャは、プロジェクト設定ファイルとして JSON形式（dub.json）と SDL形式（dub.sdl）の2種類をサポートしている。プロジェクト要件やチーム方針の変更により、フォーマットの切り替えが必要になる場合がある。エディタ内からワンクリックでフォーマット変換を実行できるようにすることで、手動変換に伴うエラーや手間を削減する。

**画面へのアクセス方法**：LSPクライアントが `served/convertDubFormat` 通知をJSON-RPCで送信する。通常はエディタのコマンドパレットから「DUB Convert Format」等のコマンドを実行する。

**主要な操作・処理内容**：
1. クライアントからJSON-RPC通知 `served/convertDubFormat` を受信する
2. 対象ファイルの存在確認とファイル名検証を行う
3. DUBの `convert` コマンドを外部プロセスとして実行する
4. 変換成功時にリネームとテキスト編集を含むWorkspaceEditを構築する
5. `workspace/applyEdit` でエディタに編集を適用する

**画面遷移**：DUBフォーマット変換フローとして独立して動作する。画面遷移図では `served/convertDubFormat` -> ファイル検証 -> `dub convert` 実行 -> `workspace/applyEdit` の流れで定義されている。

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

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 57 | DUBフォーマット変換 (served/convertDubFormat) | 主機能 | dub.json/dub.sdlファイルを別フォーマットに変換する |

## 画面種別

カスタムLSP通知（ファイル変換処理）

## URL/ルーティング

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

## 入出力項目

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

| 項目名 | 型 | 必須 | 説明 |
|--------|-----|------|------|
| textDocument | TextDocumentIdentifier | はい | 変換対象のテキストドキュメント（dub.json/dub.sdl/package.json） |
| newFormat | string | はい | 変換先のフォーマット（"json" または "sdl"） |

### 出力（通知のため直接的な戻り値なし）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| workspace/applyEdit | WorkspaceEdit | 変換成功時、ファイルリネームとテキスト編集をエディタに適用 |

## 表示項目

| 項目 | 表示形式 | 説明 |
|------|----------|------|
| エラーメッセージ | showErrorMessage | ファイル名不正時やdub convert失敗時に表示 |

## イベント仕様

### 1-通知受信

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

1. `DubConvertRequest` からパラメータをデシリアライズする
2. ファイルの存在確認を行う（存在しない場合はエラーログ出力して終了）
3. ファイル名が "dub.json", "dub.sdl", "package.json" のいずれかであることを確認する
   - 対象外の場合は `d.dub.notRecipeFile` エラーメッセージを表示して終了
4. ドキュメントマネージャからテキストドキュメントを取得する
5. 外部プロセスとして `dub convert -f {newFormat} -s` コマンドを実行する
   - stderrはパススルー、最大バッファサイズ4MB
   - 作業ディレクトリはファイルの親ディレクトリ
6. コマンドの終了コードを確認する
   - 0以外の場合は `d.dub.convertFailed` エラーメッセージを表示して終了
7. 新しいURIを構築する（拡張子をnewFormatに変更）
8. WorkspaceEditを構築する：
   - クライアントがリソース操作（rename）をサポートしている場合：
     - documentChanges にRenameFileとTextDocumentEditを設定
   - サポートしていない場合：
     - changes に元URIのTextEditを設定
9. `workspace/applyEdit` リクエストをクライアントに送信する

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

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

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| フォーマット変換 | ファイルシステム | UPDATE | workspace/applyEditを通じてDUBレシピファイルの内容とファイル名を変更 |

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

#### DUBレシピファイル

| 操作 | 項目 | 更新値 | 備考 |
|-----|------|--------|------|
| RENAME | ファイル名 | dub.{newFormat}（例: dub.json -> dub.sdl） | クライアントがrename操作をサポートしている場合 |
| UPDATE | ファイル内容 | dub convertコマンドの出力結果 | 全テキスト置換 |

## メッセージ仕様

| メッセージID | 種別 | 条件 | メッセージ内容 |
|-------------|------|------|---------------|
| d.dub.notRecipeFile | エラー | ファイル名が dub.json/dub.sdl/package.json でない場合 | "Dub format conversion only works with package recipes named dub.json, dub.sdl, package.json" |
| d.dub.convertFailed | エラー | dub convertコマンドが失敗した場合 | "The dub conversion command has failed" |

## 例外処理

| 条件 | 動作 | 返却値 |
|------|------|--------|
| ファイルが存在しない | エラーログ出力、処理中断 | (通知のため戻り値なし) |
| ファイル名が対象外 | showErrorMessage表示、処理中断 | (通知のため戻り値なし) |
| dub convertコマンド失敗 | showErrorMessage表示、処理中断 | (通知のため戻り値なし) |

## 備考

- `@protocolNotification` で登録されており、LSPの通知（notification）として処理される（レスポンスなし）
- `dub convert` コマンドは `-s` フラグ（silent）で実行される
- クライアントの `workspace.workspaceEdit.resourceOperations` ケイパビリティにrenameが含まれている場合、ファイルリネームと内容更新が一つのWorkspaceEditで行われる
- 翻訳機能（translate）を使用してエラーメッセージを多言語対応している

---

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

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

### 推奨読解順序

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

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

**読解のコツ**: `@protocolNotification` は `@protocolMethod` と異なり、レスポンスを返さない。通知として処理されるため、戻り値の型はvoidとなる。

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

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

**主要処理フロー**:
1. **513行目**: `@protocolNotification("served/convertDubFormat")` UDAで通知ハンドラとして登録
2. **518行目**: `file = req.textDocument.uri.uriToFile` - URIからファイルパス変換
3. **519行目**: `if (!fs.exists(file))` - ファイル存在確認
4. **525行目**: `if (!file.baseName.among!("dub.json", "dub.sdl", "package.json"))` - ファイル名検証
5. **527行目**: `rpc.window.showErrorMessage(translate!"d.dub.notRecipeFile")` - エラーメッセージ表示
6. **533-536行目**: `execute(["dub", "convert", "-f", req.newFormat, "-s"], ...)` - 外部プロセス実行
7. **538-541行目**: 終了コードチェックとエラーハンドリング
8. **544行目**: `newUri = req.textDocument.uri.setExtension("." ~ req.newFormat)` - 新URI構築
9. **551-556行目**: クライアントのrenameサポート判定
10. **557-563行目**: documentChanges（RenameFile + TextDocumentEdit）の構築
11. **571行目**: `rpc.sendMethod("workspace/applyEdit", params)` - 編集適用リクエスト送信

#### Step 3: 翻訳リソースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | en.txt | `views/en.txt` | d.dub.notRecipeFile（163行目）、d.dub.convertFailed（164行目）のメッセージ定義 |

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

```
LSPクライアント (エディタ コマンドパレット)
    |
    |  served/convertDubFormat (JSON-RPC notification)
    v
convertDubFormat(DubConvertRequest) [source/served/commands/dub.d:514]
    |
    +-- fs.exists(file)
    |
    +-- file.baseName.among!(...)
    |       |
    |       +-- [不正] rpc.window.showErrorMessage(translate!"d.dub.notRecipeFile")
    |
    +-- documents[uri]
    |
    +-- execute(["dub", "convert", "-f", newFormat, "-s"])
    |       |
    |       +-- [失敗] rpc.window.showErrorMessage(translate!"d.dub.convertFailed")
    |
    +-- [成功] WorkspaceEdit構築
    |       +-- capabilities.workspace.workspaceEdit.resourceOperations判定
    |       +-- [rename対応] RenameFile + TextDocumentEdit
    |       +-- [非対応] TextEdit
    |
    +-- rpc.sendMethod("workspace/applyEdit", params)
```

### データフロー図

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

JSON-RPC Notification   --->  convertDubFormat()            --->  workspace/applyEdit
  textDocument.uri               |                                  |
  newFormat: "sdl"               +-- ファイル検証                   +-- RenameFile
                                 +-- dub convert実行                   (dub.json -> dub.sdl)
                                 |   (外部プロセス)                 +-- TextDocumentEdit
                                 +-- WorkspaceEdit構築                  (変換後テキスト)
                                 +-- 編集適用リクエスト送信
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| dub.d | `source/served/commands/dub.d` | ソース | convertDubFormat関数の実装（513-572行目） |
| protoext.d | `source/served/lsp/protoext.d` | ソース | DubConvertRequest構造体定義（83-89行目） |
| types.d | `source/served/types.d` | ソース | capabilities、documents等のグローバル定義 |
| translate.d | `source/served/utils/translate.d` | ソース | 翻訳機能（translate template） |
| en.txt | `views/en.txt` | 翻訳リソース | 英語メッセージ定義 |
| ja.txt | `views/ja.txt` | 翻訳リソース | 日本語メッセージ定義 |
| extension.d | `source/served/extension.d` | ソース | LSP通知ディスパッチ基盤 |
