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

## 概要

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

### 本機能の処理概要

ifをcondに変換機能は、ネストしたif式（if-else-if-else...の連鎖）をフラットなcond式に変換する。これにより、深くネストした条件分岐を読みやすい形式に整理できる。

**業務上の目的・背景**：Clojureでは、複数の条件分岐を記述する際、ifのネストよりもcondの方が可読性が高いことが多い。既存のifネストをcond形式にリファクタリングすることで、コードの保守性と可読性を向上させることができる。

**機能の利用シーン**：
- ネストしたif-else-if-elseをcondに変換してコードを整理したい場合
- コードレビューでcondの使用を推奨された場合
- 新しい条件を追加する前にcond形式に変換したい場合
- コードの可読性を向上させたい場合

**主要な処理内容**：
1. カーソル位置のif式を特定
2. ネストしたif式を再帰的に解析
3. 各条件-結果ペアを収集
4. 最後のelse節を処理（:elseまたは省略）
5. cond式を生成
6. コメントの位置を保持

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

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

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

### 入力データソース

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

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. if式の特定
   └─ find-nearby-node関数で"if"を検索
2. if式の検証
   └─ is-if-expr?でif式かどうか確認
3. cond式の構築開始
   └─ "(cond)"の空のcond式を生成
4. if式の再帰的処理
   └─ loopで条件-結果ペアを収集
5. コメントの処理
   └─ gather-comments-leftでコメントを収集
6. :else節の追加
   └─ else部分がある場合は:elseを追加
7. 結果の返却
   └─ rangeとlocを含むマップのベクターを返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[find-nearby-node if]
    B --> C{if式?}
    C -->|No| D[エラー返却]
    C -->|Yes| E[空のcond生成]
    E --> F[条件式取得]
    F --> G[真の場合の式取得]
    G --> H[コメント収集]
    H --> I[cond節追加]
    I --> J[偽の場合の式取得]
    J --> K{偽の式もif?}
    K -->|Yes| F
    K -->|No| L{偽の式あり?}
    L -->|Yes| M[:else節追加]
    L -->|No| N[結果返却]
    M --> N
    N --> O[終了]
    D --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | 条件-結果ペア | if式の条件と真の場合の式をcondの条件-結果ペアに変換 | 各if式 |
| BR-002 | ネストif処理 | else部分がifの場合、再帰的にcond節に追加 | else部がif式の場合 |
| BR-003 | :else追加 | 最後のelse節は:elseキーワードで追加 | else部がif式でない場合 |
| BR-004 | else省略 | elseがない場合は:elseなしのcondを生成 | else部がない場合 |
| BR-005 | コメント保持 | 条件式の前のコメントを保持 | コメントがある場合 |
| BR-006 | インデント調整 | cond内のインデントを元のif式に合わせる | 常時 |

### 計算ロジック

特になし。

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| :invalid-params | エラー | if式でない場合 | "Not an if expression"メッセージ返却 |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

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

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

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

## 備考

- near-if?関数で近くにif式があるかどうかを判定
- 単一のif式もcondに変換可能（2つの節を持つcondになる）

---

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

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

### 推奨読解順序

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

if式の判定とcond式の構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | near-if?関数（1141-1144行目）でif式の判定 |
| 1-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | find-nearby-node関数（1114-1133行目）で近くのノード検索 |

**読解のコツ**: find-nearby-nodeはカーソル位置からif/condなどの特定のノードを検索する汎用関数。

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

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

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

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | is-if-expr?（1151-1154行目）でif式判定 |
| 3-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | gather-comments-left（1156-1161行目）でコメント収集 |
| 3-3 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | if->cond（1177-1233行目）でメイン処理 |

**主要処理フロー**:
- **1177-1185行目**: if式の検索とcond式の初期化
- **1186-1207行目**: loopで再帰的にif式を処理
- **1189行目**: if-test-expr（条件）の取得
- **1190行目**: if-true-expr（真の場合）の取得
- **1192行目**: if-false-expr（偽の場合）の取得
- **1193-1206行目**: cond節の構築
- **1207行目**: 次のif式（else部）へ再帰
- **1209-1232行目**: else部の処理と結果返却

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

```
call-command (command.clj)
    │
    └─ run-command :if->cond-refactor (command.clj:149-150)
           │
           └─ r.transform/if->cond (transform.clj:1177-1233)
                  │
                  ├─ find-nearby-node "if" (transform.clj:1114-1133)
                  │
                  ├─ is-if-expr? (transform.clj:1151-1154)
                  │
                  ├─ gather-comments-left (transform.clj:1156-1161)
                  │
                  ├─ insert-cond-case-part (transform.clj:1135-1139)
                  │
                  └─ loop [再帰的if処理]
```

### データフロー図

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

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

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | ソース | if->cond変換処理の実装 |
| 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` | テスト | if->cond変換のテスト |
