# 機能設計書 29-condをifに変換

## 概要

本ドキュメントは、clojure-lspの「condをifに変換」機能（cond->if-refactorコマンド）の設計仕様を定義する。この機能は、cond式を等価なネストしたif式に変換するリファクタリング機能を提供する。

### 本機能の処理概要

condをifに変換機能は、cond式をネストしたif式（if-else-if-else...の連鎖）に変換する。これは「ifをcondに変換」機能の逆操作であり、特定の条件分岐を強調したい場合や、if形式の方が適切な場面で使用する。

**業務上の目的・背景**：Clojureではcond式が一般的に推奨されるが、2つの分岐のみの場合や、特定の条件を強調したい場合はif式の方が適切なことがある。この機能により、cond式からif式への変換を効率的に行える。

**機能の利用シーン**：
- 2つの条件分岐のみのcondをシンプルなifに変換したい場合
- 特定の条件分岐を強調したい場合
- if形式の方がコードの意図が明確になる場合
- 既存コードのスタイルに合わせたい場合

**主要な処理内容**：
1. カーソル位置のcond式を特定
2. cond式の偶数性を検証（条件-結果ペア）
3. 各条件-結果ペアをネストしたif式に変換
4. :elseまたはキーワード条件を処理
5. コメントの位置を保持
6. ネストしたif式を生成

**関連システム・外部連携**：LSPプロトコルを通じてエディタと連携し、コードアクションまたはコマンドとして実行される。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはLSPサーバーであり、UI画面は存在しない。エディタのコードアクションメニューから呼び出される。 |

## 機能種別

リファクタリング（コード変換処理）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| zloc | zipper location | Yes | カーソル位置のzipperロケーション | cond式の近くにあること |

### 入力データソース

- エディタから送信されるLSPリクエスト
- ドキュメントのパース結果（rewrite-clj zipper）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | map | 変更対象範囲（:row, :col, :end-row, :end-col） |
| loc | zipper location | 変換後のネストしたif式 |

### 出力先

LSPプロトコルを通じてエディタに返却され、テキスト編集として適用される。

## 処理フロー

### 処理シーケンス

```
1. cond式の特定
   └─ find-nearby-node関数で"cond"を検索
2. cond式の検証
   └─ 偶数の節があることを確認
3. ダミーノードの作成
   └─ ネスト構築のためのルートノード
4. 条件-結果ペアの処理
   └─ loopで各ペアを処理
5. if式の構築
   └─ 各ペアをネストしたif式に変換
6. :else/キーワード処理
   └─ 最後のキーワード条件はtrueに変換
7. コメントの処理
   └─ gather-comments-leftでコメントを収集
8. 結果の返却
   └─ rangeとlocを含むマップのベクターを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[find-nearby-node cond]
    B --> C{cond式?}
    C -->|No| D[エラー返却]
    C -->|Yes| E{偶数の節?}
    E -->|No| F[エラー返却]
    E -->|Yes| G[ダミーノード作成]
    G --> H[条件-結果ペア取得]
    H --> I{キーワード条件?}
    I -->|Yes| J{最後のペア?}
    J -->|Yes| K[結果のみ追加]
    J -->|No| L[trueに変換してif追加]
    I -->|No| M[if式追加]
    K --> N{次のペアあり?}
    L --> N
    M --> N
    N -->|Yes| H
    N -->|No| O[結果返却]
    O --> P[終了]
    D --> P
    F --> P
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 偶数検証 | cond式は偶数の節を持つ必要がある | 常時 |
| BR-002 | if生成 | 各条件-結果ペアをネストしたifに変換 | 各ペア |
| BR-003 | キーワード変換 | :elseなどのキーワード条件はtrueに変換 | キーワード条件の場合 |
| BR-004 | 最後のelse | 最後のキーワード条件はelseとして処理（if不要） | 最後のペアがキーワードの場合 |
| BR-005 | 空cond処理 | 空のcondはnilを返す | 節がない場合 |
| BR-006 | コメント保持 | 条件式の前のコメントを保持 | コメントがある場合 |
| BR-007 | インデント調整 | ネストレベルに応じたインデント | 常時 |

### 計算ロジック

特になし。

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| :invalid-params | エラー | cond式でない場合 | "Not a cond"メッセージ返却 |
| :invalid-params | エラー | 奇数の節がある場合 | "Requires an even number of forms"メッセージ返却 |

### リトライ仕様

リトライは不要。

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

該当なし（メモリ上の操作のみ）。

## パフォーマンス要件

即座に完了すること（100ms以内）。

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

特になし。ローカルファイルの操作のみ。

## 備考

- near-cond?関数で近くにcond式があるかどうかを判定
- check-for-cond-errorsで事前にエラーを検出
- 空のcondは(cond)をnilに変換

---

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

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

### 推奨読解順序

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

cond式の判定とエラーチェックを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | near-cond?関数（1146-1149行目）でcond式の判定 |
| 1-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | check-for-cond-errors関数（1274-1284行目）でエラーチェック |

**読解のコツ**: check-for-cond-errorsは「condでない」と「奇数の節」の2種類のエラーをチェック。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.clj | `lib/src/clojure_lsp/feature/command.clj` | cond->if-refactorコマンドの定義（152-153行目） |
| 2-2 | code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | refactor-cond->if-actionでUIアクション生成（227-232行目） |

**主要処理フロー**:
1. **152-153行目**: run-commandのcond->if-refactorメソッドがr.transform/cond->ifを呼び出し

#### Step 3: 変換処理の実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | keyword->true-node（1235-1245行目）でキーワード処理 |
| 3-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | insert-if-test/insert-if-result（1247-1265行目）でif構築 |
| 3-3 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | cond->if（1289-1337行目）でメイン処理 |

**主要処理フロー**:
- **1289-1293行目**: cond式の検索とエラーチェック
- **1296-1328行目**: loopで各条件-結果ペアを処理
- **1300-1304行目**: コメントの収集
- **1305-1309行目**: キーワード条件（:else等）の判定
- **1310-1324行目**: if式の構築（最後のelse or ネストif）
- **1331-1336行目**: 最終結果の返却

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

```
call-command (command.clj)
    │
    └─ run-command :cond->if-refactor (command.clj:152-153)
           │
           └─ r.transform/cond->if (transform.clj:1289-1337)
                  │
                  ├─ find-nearby-node "cond" (transform.clj:1114-1133)
                  │
                  ├─ check-for-cond-errors (transform.clj:1274-1284)
                  │
                  ├─ gather-comments-left (transform.clj:1156-1161)
                  │
                  ├─ keyword->true-node (transform.clj:1235-1245)
                  │
                  ├─ insert-if-test (transform.clj:1247-1251)
                  │
                  ├─ insert-if-result (transform.clj:1261-1265)
                  │
                  └─ loop [再帰的if構築]
```

### データフロー図

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

LSPリクエスト ───▶ zloc取得 ───▶ find-nearby-node ───▶ cond解析 ───▶ if構築 ───▶ TextEdit
(uri, pos)                              │              │
                                        └─ cond検索    └─ ネスト生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | ソース | cond->if変換処理の実装 |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクションUI生成 |
| transform_test.clj | `lib/test/clojure_lsp/refactor/transform_test.clj` | テスト | cond->if変換のテスト |
