# 機能設計書 13-Thread Last All

## 概要

本ドキュメントは、clojure-lspのThread Last All機能の設計を記述する。この機能はネストされたClojure式を`->>`（thread-last）マクロ形式に完全に変換するリファクタリング機能である。

### 本機能の処理概要

Thread Last All機能は、ネストされた関数呼び出しを`->>`マクロを使用した読みやすい形式に変換する。

**業務上の目的・背景**：Clojureコードでは、コレクション処理において関数の結果を次の関数の最後の引数として渡すパターンが頻繁に使用される（map, filter, reduce等）。深くネストされた式は読みにくく、保守性が低下する。`->>`マクロを使用することで、データの流れを上から下への線形な形式で表現でき、特にコレクション処理のパイプラインの可読性が大幅に向上する。

**機能の利用シーン**：
- コレクション処理のパイプラインを読みやすく整形したい場合
- map, filter, reduce等の連鎖をリファクタリングしたい場合
- コードレビューで指摘された深いネストを解消したい場合
- 既存コードのリファクタリング時

**主要な処理内容**：
1. カーソル位置の式がスレッド可能かどうかを判定
2. ネストされた式を再帰的に展開
3. 各関数呼び出しの最後の引数を抽出して前段に移動
4. 単一引数の括弧を設定に応じて削除
5. 適切なインデントで`->>`形式に再構築

**関連システム・外部連携**：rewrite-cljライブラリを使用してASTを操作する。

**権限による制御**：特になし。すべてのユーザーが利用可能。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| N/A | エディタ | 主画面 | LSPクライアント（VS Code等）からコードアクションまたはコマンドとして実行 |

## 機能種別

リファクタリング / コード変換

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uri | string | Yes | 対象ファイルのURI | file://形式のURI |
| row | integer | Yes | カーソル位置の行番号（1-indexed） | 正の整数 |
| col | integer | Yes | カーソル位置の列番号（1-indexed） | 正の整数 |

### 入力データソース

- LSPクライアントからのtextDocument/codeActionリクエスト
- LSPクライアントからのworkspace/executeCommandリクエスト（thread-last-allコマンド）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| range | Range | 編集対象の範囲（変換対象の式全体） |
| newText | string | thread-last形式に変換後のテキスト |

### 出力先

- LSPクライアントへWorkspaceEditとして返却

## 処理フロー

### 処理シーケンス

```
1. スレッド可能性の判定
   └─ can-thread?関数でリスト形式かつ有効な式かを確認

2. 初回のスレッド処理
   └─ thread-sym関数で最後の引数を抽出

3. 再帰的なスレッド処理
   └─ ネストされた式がある限りthread-symを繰り返し適用

4. 単一引数の括弧削除（設定による）
   └─ :keep-parens-when-threading?がfalseの場合、括弧を削除

5. インデント調整
   └─ 各行を適切にインデント

6. 編集結果の生成
   └─ 範囲とloc（編集後のジッパー）を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[can-thread?判定]
    B --> C{スレッド可能?}
    C -->|No| D[nil返却]
    C -->|Yes| E[thread-sym実行]
    E --> F[最後の引数を抽出]
    F --> G[->>形式でラップ]
    G --> H{ネストされた式あり?}
    H -->|Yes| I[次の式をthread-sym]
    I --> H
    H -->|No| J[単一引数括弧削除判定]
    J --> K[インデント調整]
    K --> L[編集結果生成]
    L --> M[終了]
    D --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | スレッド不可シンボル | defn, def, ns, :require, :import, when, if, comment等はスレッド対象外 | thread-invalid-symbolsに含まれる |
| BR-02 | 最後の引数抽出 | ネストされた式の最後の引数を抽出して前段に移動 | リスト形式の式 |
| BR-03 | 単一引数括弧削除 | 引数が1つの場合、設定により括弧を削除 | :keep-parens-when-threading?がfalse |
| BR-04 | インデント計算 | ->>シンボルの長さ+列位置に基づいてインデント | 常に適用 |
| BR-05 | 再帰的展開 | can-thread-list?がtrueである限り再帰的に展開 | ネストされた式が存在 |

### 計算ロジック

- インデント幅: `(+ (count (str sym)) (:col top-meta))` で計算
- 最後の引数の位置: `(comp z/rightmost z/right)` で取得

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

本機能はデータベース（db）を読み取り専用で使用する。

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 設定取得 | :settings | SELECT | :keep-parens-when-threading?設定を参照 |

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| N/A | nil返却 | スレッド不可能な式 | nilを返却（何もしない） |
| N/A | 空リスト | 有効な変換対象がない | 空リストを返却 |

### リトライ仕様

特になし。同期的に1回のみ実行。

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

- クライアントに編集結果を返却するのみで、サーバー側でのトランザクション管理は不要

## パフォーマンス要件

- 再帰的な処理だが、通常のネスト深度（~10レベル）では即時完了
- 極端に深いネストでもスタックオーバーフローしないようloop/recurを使用

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

- ファイルシステムへの直接書き込みは行わない（LSP経由でクライアントに委譲）

## 備考

- 変換例:
  - 入力: `(remove nil? (filter :id (map (comp now doit) xs)))`
  - 出力:
    ```clojure
    (->> xs
         (map (comp now doit))
         (filter :id)
         (remove nil?))
    ```
- Thread First All（->）との違い:
  - `->` は第一引数に挿入
  - `->>` は最後の引数に挿入
- コレクション処理（map, filter, reduce等）は通常`->>`が適切

---

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

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

### 推奨読解順序

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

スレッド処理で使用される定数と設定を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | thread-invalid-symbols定数（110-112行目） |
| 1-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | thread-last-symbols定義（159行目）: `#{'->> 'some->>}` |

**読解のコツ**: thread-last-symbolsには`->>`と`some->>`が含まれる。これらのシンボルは既にスレッド化された式を判定するために使用される。

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

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | command.clj | `lib/src/clojure_lsp/feature/command.clj` | run-command :thread-last-all（116-117行目） |
| 2-2 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | thread-last-all関数（154-156行目） |

**主要処理フロー**:
1. **154行目**: `thread-last-all`関数定義
2. **156行目**: `thread-all`を`'->>`シンボルで呼び出し

#### Step 3: thread-all関数を理解する

全展開の核となるループ処理を理解する（Thread First Allと共通）。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | thread-all関数（138-148行目） |

**主要処理フロー**:
- **139行目**: シンボル（`'->>`）を引数として受け取る
- **143行目**: `thread-sym`に`->>`を渡して初回変換
- **146行目**: `can-thread-list?`で継続判定

#### Step 4: thread-sym関数を理解する

個別のスレッド変換ロジックを理解する。`->>`の場合の動作に注目。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | thread-sym関数（69-108行目） |

**主要処理フロー**:
- **72行目**: movement計算 - `->>`の場合は`(comp z/rightmost z/right)`で最後の引数を取得
- **73行目**: first-locで最後の引数位置を取得

#### Step 5: Thread FirstとThread Lastの違いを理解する

2つのスレッドマクロの違いを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | movement関数の条件分岐（72行目） |

**読解のコツ**:
- `->` の場合: `z/right` で第一引数（関数名の次）を取得
- `->>` の場合: `(comp z/rightmost z/right)` で最後の引数を取得

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

```
handlers/execute-command
    │
    └─ f.command/call-command
           │
           └─ run-command :thread-last-all
                  │
                  └─ r.transform/thread-last-all
                         │
                         └─ thread-all (sym = '->>)
                                │
                                ├─ can-thread?
                                │      └─ can-thread-list?
                                │
                                └─ loop
                                       │
                                       └─ thread-sym (sym = '->>)
                                              │
                                              ├─ z/rightmost, z/right (最後の引数抽出)
                                              │
                                              ├─ edit/single-child?
                                              │      └─ edit/raise (括弧削除)
                                              │
                                              └─ edit/wrap-around :list
```

### データフロー図

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

zloc ─────────────────┬─> can-thread? ────────────> boolean
                      │
                      └─> thread-all (sym = '->>)
                              │
                              ├─> thread-sym (1回目)
                              │       │
                              │       ├─> last-node抽出 (z/rightmost)
                              │       └─> ->>形式でラップ
                              │
                              └─> loop (再帰)
                                      │
                                      └─> thread-sym (N回目)
                                              │
                                              └─────────────> [{:range :loc}]
                                                                   │
                                                                   └─> WorkspaceEdit
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| transform.clj | `lib/src/clojure_lsp/refactor/transform.clj` | ソース | スレッド変換のメインロジック |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンドディスパッチャー |
| code_actions.clj | `lib/src/clojure_lsp/feature/code_actions.clj` | ソース | コードアクション提供 |
| edit.clj | `lib/src/clojure_lsp/refactor/edit.clj` | ソース | ジッパー操作ユーティリティ |
| transform_test.clj | `lib/test/clojure_lsp/refactor/transform_test.clj` | テスト | 単体テスト |
