# 機能設計書 25-分割代入解除

## 概要

本ドキュメントは、clojure-lspの「分割代入解除」機能（restructure-keysコマンド）の設計仕様を定義する。この機能は、分割代入（destructuring）形式を通常のマップアクセス形式に戻すリファクタリング機能を提供する。

### 本機能の処理概要

分割代入解除機能は、{:keys [...]}や{:syms [...]}などの分割代入形式を、通常のキーワードアクセス（`(:key element)`）やシンボルアクセス（`('sym element)`）の形式に展開する。例えば、`(let [{:keys [a b]} data] a b)`を`(let [element data] (:a element) (:b element))`に変換する。

**業務上の目的・背景**：分割代入はClojureの便利な機能だが、すべての場面で適切とは限らない。マップの構造が変わる可能性がある場合や、キーアクセスを明示的にしたい場合、デバッグ時に中間変数を確認したい場合などに、分割代入を解除する必要がある。この機能により、分割代入の解除を効率的に行える。

**機能の利用シーン**：
- マップの構造変更に備えて分割代入を解除したい場合
- デバッグのために中間変数を明示的にしたい場合
- コードの可読性を変更したい場合
- 分割代入の対象キーを動的に変更したい場合

**主要な処理内容**：
1. カーソル位置の分割代入マップを特定
2. 分割代入のキー（:keys、:syms）と値を解析
3. 新しい変数名（element）を生成
4. 各ローカル変数の使用箇所を検索
5. 使用箇所を`(:key element)`形式に変換
6. 元の分割代入を変数名で置換

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

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| zloc | zipper location | Yes | カーソル位置のzipperロケーション | 分割代入マップ内にあること |
| uri | string | Yes | 対象ファイルのURI | 有効なURI形式 |
| db | database | Yes | LSPデータベース | - |

### 入力データソース

- エディタから送信されるLSPリクエスト
- ドキュメントのパース結果（rewrite-clj zipper）
- clj-kondo解析データ（ローカル変数使用箇所の検索）

## 出力仕様

### 出力データ

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

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. 分割代入マップの特定
   └─ map-to-restructure関数で分割代入マップを検索
2. ローカル変数の存在確認
   └─ q/find-locals-under-formで分割代入内のローカル変数を確認
3. 分割代入キーの解析
   └─ :keys、:syms、:as、:or などのキーを解析
4. 新変数名の生成
   └─ unshadowed-element-name関数で衝突しない変数名を生成
5. 使用箇所の変換データ生成
   └─ restructure-data関数で各ローカル変数の変換情報を生成
6. 使用箇所の置換
   └─ restructure-edits関数で(:key element)形式に変換
7. 元の分割代入の置換
   └─ 変数名または残りの分割代入で置換
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{分割代入マップ?}
    B -->|No| C[nil返却]
    B -->|Yes| D{ローカル変数あり?}
    D -->|No| C
    D -->|Yes| E[分割代入キー解析]
    E --> F[新変数名生成]
    F --> G[使用箇所変換データ生成]
    G --> H{すべて変換可能?}
    H -->|Yes| I[変数名で置換]
    H -->|No| J[残り分割代入 + :as で置換]
    I --> K[使用箇所置換]
    J --> K
    K --> L[結果返却]
    L --> M[終了]
    C --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-001 | :keys変換 | {:keys [a]} の a を (:a element) に変換 | :keysキーの場合 |
| BR-002 | :syms変換 | {:syms [a]} の a を ('a element) に変換 | :symsキーの場合 |
| BR-003 | 名前空間修飾 | {:ns/keys [a]} の a を (:ns/a element) に変換 | 名前空間修飾:keysの場合 |
| BR-004 | 自動解決 | {::keys [a]} の a を (::a element) に変換 | 自動解決:keysの場合 |
| BR-005 | 変数名衝突回避 | elementが既存変数と衝突する場合、element-1, element-2...を使用 | 変数名衝突時 |
| BR-006 | :or処理 | デフォルト値がある場合、(get element :key default)形式を使用 | :orが指定されている場合 |
| BR-007 | 部分変換 | ネストした分割代入など変換不可の部分は残す | 変換不可要素がある場合 |

### 計算ロジック

特になし。

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

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

本機能はデータベース操作を行わない。clj-kondo解析データの読み取りのみ。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 暗黙的エラー | 分割代入マップでない場合 | nil返却 |
| - | 暗黙的エラー | 分割代入内にローカル変数がない場合 | nil返却 |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

使用箇所の検索を含め、1秒以内に完了すること。

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

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

## 備考

- 名前空間付きマップ（#:ns{:keys [...]}）にも対応
- :asで既に指定されている変数名がある場合はそれを使用

---

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

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

### 推奨読解順序

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

分割代入の解析と変換データの構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | restructure-data関数（73-141行目）で変換データの構造 |

**読解のコツ**: restructure-dataは各分割代入エントリを解析し、:restructure?、:replace-with、:reference-elemsを含むマップを返す。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.clj | `lib/src/clojure_lsp/feature/command.clj` | restructure-keysコマンドの定義（56-57行目） |
| 2-2 | code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | restructure-keys-actionでUIアクション生成（189-194行目） |

**主要処理フロー**:
1. **56-57行目**: run-commandのrestructure-keysメソッドがf.restructure-keys/restructure-keysを呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | map-to-restructure（11-34行目）で分割代入マップを特定 |
| 3-2 | restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | can-restructure-keys?（36-37行目）で可能性判定 |
| 3-3 | restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | unshadowed-element-name（153-170行目）で変数名生成 |
| 3-4 | restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | restructure-keys（172-220行目）でメイン処理 |

**主要処理フロー**:
- **11-34行目**: map-to-restructure関数で分割代入マップを検索（マップ、名前空間付きマップ対応）
- **73-141行目**: restructure-data関数で:keys/:symsの変換情報を生成
- **143-151行目**: restructure-edits関数で使用箇所の置換データを生成
- **153-170行目**: unshadowed-element-name関数で衝突しない変数名を生成
- **172-220行目**: restructure-keys関数で全体の処理を実行

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

```
call-command (command.clj)
    │
    └─ run-command :restructure-keys (command.clj:56-57)
           │
           └─ f.restructure-keys/restructure-keys (restructure_keys.clj:172-220)
                  │
                  ├─ map-to-restructure (restructure_keys.clj:11-34)
                  │      └─ z/map? z/namespaced-map?
                  │
                  ├─ z-children-seq (restructure_keys.clj:39-43)
                  │
                  ├─ unshadowed-element-name (restructure_keys.clj:153-170)
                  │      └─ q/find-local-usages-under-form
                  │
                  ├─ restructure-data (restructure_keys.clj:73-141)
                  │      └─ reference-elems → q/find-references
                  │
                  └─ restructure-edits (restructure_keys.clj:143-151)
                         └─ z-of-list
```

### データフロー図

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

LSPリクエスト ───▶ zloc取得 ───▶ map-to-restructure ───▶ 変数名生成 ───▶ 変換データ生成 ───▶ 置換 ───▶ TextEdit
(uri, pos)                              │                     │
                                        └─ マップ検索         └─ 衝突回避
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| restructure_keys.clj | `lib/src/clojure_lsp/feature/restructure_keys.clj` | ソース | 分割代入解除処理の実装 |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクションUI生成 |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | ローカル変数使用箇所の検索 |
| restructure_keys_test.clj | `lib/test/clojure_lsp/feature/restructure_keys_test.clj` | テスト | 分割代入解除のテスト |
