# 機能設計書 36-get-in展開

## 概要

本ドキュメントは、Clojure LSPの「get-in展開」機能の設計仕様を記載する。この機能は、`get`または`get-in`形式のマップアクセスを、キーワード関数形式のネストアクセス（例：`(:a (:b m))`）に展開するリファクタリング操作を提供する。

### 本機能の処理概要

**業務上の目的・背景**：get-in形式とキーワード関数形式にはそれぞれ利点がある。キーワード関数形式はより簡潔で、単純なアクセスパターンでは可読性が高い。本機能は、get/get-in形式をキーワード関数形式に変換することで、コードスタイルの統一や簡潔な記述への変更を支援する。

**機能の利用シーン**：この機能は以下の場面で利用される：
- get-in形式からキーワード関数形式への変換
- コードの簡潔化
- デフォルト値が不要になった場合の簡略化

**主要な処理内容**：
1. カーソル位置の式がget/get-in呼び出しか判定
2. `get-in-less`: 1段階展開（get-in → get、get → キーワード関数）
3. `get-in-none`: 可能な限りすべてをキーワード関数形式に展開

**関連システム・外部連携**：LSPプロトコルを通じてエディタと連携。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | エディタ画面 | 主画面 | コードアクションメニューから展開操作を選択 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 対象ファイルのURI | 有効なファイルURIであること |
| line | number | Yes | カーソル行（0-indexed） | 0以上の整数 |
| character | number | Yes | カーソル列（0-indexed） | 0以上の整数 |

### 入力データソース

- エディタからのLSP `workspace/executeCommand` リクエスト
- コマンド名: `get-in-less` または `get-in-none`

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| edits | vector | テキスト編集のリスト |

### 出力先

- LSPレスポンスとしてエディタに返却

## 処理フロー

### 処理シーケンス

```
1. リクエスト受信
   └─ コマンドと引数を取得

2. 展開可否判定
   └─ get-in-less-data で展開可能か判定
   └─ デフォルト値とキーの型をチェック

3. get-in-less の場合
   └─ 1段階の展開を実行
   └─ (get-in m [:a :b]) → (get (:a m) :b)
   └─ (get m :key) → (:key m)

4. get-in-none の場合
   └─ 再帰的にget-in-lessを適用
   └─ 展開不可になるまで繰り返し

5. 結果の返却
   └─ 編集操作を返却
```

### フローチャート

```mermaid
flowchart TD
    A[コマンド受信] --> B{get/get-in呼び出し?}
    B -->|No| C[nil返却]
    B -->|Yes| D{デフォルト値あり?}
    D -->|Yes| E{キーがキーワード/シンボル?}
    D -->|No| F[展開可能]
    E -->|No| C
    E -->|Yes| F
    F --> G{get-in-less?}
    G -->|Yes| H[1段階展開]
    G -->|No| I[get-in-none]
    I --> J{まだ展開可能?}
    J -->|Yes| H
    H --> J
    J -->|No| K[編集返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | get展開 | `(get m :key)` → `(:key m)` | getの引数がキーワードの場合 |
| BR-36-02 | get-in縮小 | `(get-in m [:a :b])` → `(get (:a m) :b)` | get-inのパスが2要素以上の場合 |
| BR-36-03 | get-in展開 | `(get-in m [:a])` → `(:a m)` | get-inのパスが1要素の場合 |
| BR-36-04 | デフォルト値制限 | デフォルト値がある場合はキーワード/クォートシンボルのみ展開可 | デフォルト値引数がある場合 |

### 計算ロジック

**展開パターン**：

1. get → キーワード関数：`(get m :key)` → `(:key m)`
2. get-in → get：`(get-in m [:a :b])` → `(get (:a m) :b)`
3. get-in → キーワード関数：`(get-in m [:a])` → `(:a m)`

**デフォルト値の扱い**：
- デフォルト値がある場合、キーワード関数はアリティ2をサポートするため変換可能
- ただし、キーワードまたはクォートされたシンボルの場合のみ

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | データベース操作なし |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 操作不可 | 展開対象でない式 | nil返却 |
| - | 操作不可 | デフォルト値ありでキーが式の場合 | nil返却 |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。

## パフォーマンス要件

- 応答時間: 50ms以内

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

- ファイルシステムへの書き込みは行わない

## 備考

- get-in-moreおよびget-in-all機能と対をなす
- デフォルト値の扱いに注意が必要

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | thread_get.clj | `lib/src/clojure_lsp/feature/thread_get.clj` | get-in-less-dataの戻り値構造 |

**読解のコツ**: `get-in-less-data`は以下のマップを返す：
- `:replace-with` - 置換後の形式（`:key`または`get`/`get-in`のzloc）
- `:map-loc` - マップ引数のzloc
- `:key-loc` - キーのzloc
- `:path-loc` - 残りのパスのzloc（get-inの場合）
- `:default-loc` - デフォルト値のzloc

**主要処理フロー**:
- **58-87行目**: `get-in-less-data` - 展開データの抽出

#### Step 2: コア機能を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | thread_get.clj | `lib/src/clojure_lsp/feature/thread_get.clj` | get-in-less*とget-in-none* |

**主要処理フロー**:
- **89-94行目**: `get-in-less*` - 1段階の展開を実行
- **96-99行目**: `get-in-none*` - 再帰的に全展開を実行
- **109行目**: `can-get-in-less?` - 展開可否判定
- **110行目**: `get-in-less` - 公開API（1段階展開）
- **111行目**: `get-in-none` - 公開API（全展開）

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

```
workspace/executeCommand (LSP)
    │
    └─ command/call-command
           │
           ├─ run-command :get-in-less
           │     └─ f.thread-get/get-in-less
           │           ├─ get-in-less-data
           │           ├─ get-in-less*
           │           └─ edits
           │
           └─ run-command :get-in-none
                 └─ f.thread-get/get-in-none
                       ├─ get-in-none* (再帰)
                       │     ├─ get-in-less-data
                       │     └─ get-in-less*
                       └─ edits
```

### データフロー図

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

zloc               ──▶  get-in-less-data           ──▶  {:replace-with, :key-loc, :path-loc, ...}
                         (展開データ抽出)

展開データ          ──▶  get-in-less*               ──▶  新しいzloc
                         (1段階展開)

新zloc             ──▶  get-in-none* (再帰)         ──▶  最終zloc
                         (全展開)

最終zloc           ──▶  edits                      ──▶  [{:range, :loc}]
                         (編集生成)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| thread_get.clj | `lib/src/clojure_lsp/feature/thread_get.clj` | ソース | get-in展開のコアロジック |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチ |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクション生成 |
| thread_get_test.clj | `lib/test/clojure_lsp/feature/thread_get_test.clj` | テスト | get-in展開のテスト |
