# 機能設計書 74-フォーマット実行

## 概要

本ドキュメントは、clojure-lsp の API として提供される `format!` 関数の機能設計を記述する。この関数は cljfmt を内部的に使用してコードのフォーマット（整形）を実行する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：Clojure プロジェクトでコードスタイルの一貫性を維持するため、自動フォーマット機能が必要である。この機能は cljfmt ライブラリを使用してコードを整形し、プロジェクト全体または指定した名前空間/ファイルに対してフォーマットを適用する。

**機能の利用シーン**：CI/CD パイプラインでのフォーマットチェック（dry モード）、コミット前のフォーマット適用、IDE 外でのバッチフォーマット処理などで利用される。

**主要な処理内容**：
1. プロジェクトの解析（最小限の解析）
2. 対象名前空間/ファイルの特定
3. 各ファイルに対して cljfmt フォーマットを実行
4. 変更の適用または差分レポート

**関連システム・外部連携**：cljfmt（コードフォーマッタ）、:style/indent メタデータによるカスタムインデント。

**権限による制御**：呼び出し元プロセスのファイルシステム権限に依存。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 該当なし | 該当なし | 該当なし | 本プロジェクトは LSP サーバー実装であり UI 画面は存在しない |

## 機能種別

ファイル更新 / 計算処理 / レポート出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| :project-root | java.io.File | No | プロジェクトルートディレクトリ | nil または存在する File |
| :namespace | Collection of Symbols | No | 対象名前空間のコレクション | nil または coll? |
| :filenames | Collection of Files | No | 対象ファイルのコレクション | nil または coll? |
| :ns-exclude-regex | Pattern | No | 除外する名前空間の正規表現 | nil または Pattern |
| :dry? | Boolean | No | true の場合はファイル変更せず差分のみ表示 | boolean |
| :settings | Map | No | clojure-lsp 設定マップ | nil または map? |

### 入力データソース

- ファイルシステム（プロジェクトソースファイル）
- .cljfmt.edn 設定ファイル
- :style/indent メタデータ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| :result-code | Integer | 0: 変更なし/完了、1: 変更あり（dry モード） |
| :message-fn | Function | 結果を文字列化する関数 |
| :edits | Collection | 編集内容のコレクション |

### 出力先

- ファイルシステム（dry? が false の場合）
- 戻り値として差分情報

## 処理フロー

### 処理シーケンス

```
1. パラメータバリデーション
   └─ :project-root、:namespace、:filenames の事前条件チェック
2. プロジェクト解析
   └─ project-namespaces-only で最小限の解析
3. 対象 URI の特定
   └─ namespace/filenames から URI リストを生成
4. フォーマット実行
   └─ 各 URI に対して handlers/formatting を実行
5. 編集適用または差分生成
   └─ dry? に応じて処理を分岐
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{パラメータ有効?}
    B -->|No| C[AssertionError]
    B -->|Yes| D[API セットアップ]
    D --> E[プロジェクト解析]
    E --> F[対象 URI 特定]
    F --> G[各 URI をフォーマット]
    G --> H{編集あり?}
    H -->|No| I[Nothing to format!]
    H -->|Yes| J{dry? モード?}
    J -->|Yes| K[差分を生成し返却]
    J -->|No| L[ファイルに適用]
    L --> M[Formatted X namespaces]
    I --> N[終了]
    K --> N
    M --> N
    C --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-74-1 | dry モード | :dry? が true の場合はファイル変更せず差分のみ表示 | :dry? が true |
| BR-74-2 | 最小解析 | :project-namespaces-only でパフォーマンス最適化 | 常時 |
| BR-74-3 | 並列処理 | pmap でファイルを並列にフォーマット | 常時 |
| BR-74-4 | 除外フィルタ | :ns-exclude-regex にマッチする名前空間は除外 | :ns-exclude-regex が指定された場合 |

### 計算ロジック

cljfmt による整形ルール：
- インデント（:indents 設定）
- 空白の正規化
- 括弧の配置

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| 該当なし | 該当なし | 該当なし | RDB は使用しない |

### テーブル別操作詳細

atom によるインメモリデータベースを参照。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| AssertionError | バリデーションエラー | パラメータ不正 | 有効なパラメータを渡す |

### リトライ仕様

リトライ機構は実装されていない。

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

RDB を使用しないため、トランザクション管理は不要。ファイル更新は各ファイル単位で実行。

## パフォーマンス要件

- pmap による並列処理で高速化
- :project-namespaces-only で解析を最小化

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

- ファイルシステムアクセスはプロセス権限に依存
- ファイル変更はプロジェクト内のみ

## 備考

- :style/indent メタデータによるカスタムインデントは、完全な解析が必要なため :analysis :type 設定が必要
- dry モードは CI/CD でのフォーマットチェックに有用

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | format.clj | `lib/src/clojure_lsp/feature/format.clj` | フォーマット編集の構造 |

**読解のコツ**: TextEdit 構造（:range、:new-text）を理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | api.clj | `lib/src/clojure_lsp/api.clj` | format! 関数定義 |

**主要処理フロー**:
1. **170-208行目**: `format!` 関数定義、docstring と事前条件

#### Step 3: 内部 API 実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | format!* の実装 |

**主要処理フロー**:
- **374-401行目**: format!* で並列フォーマット実行
- **378行目**: dynamic-setup-project-analysis! で :project-namespaces-only 解析

#### Step 4: ハンドラーを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | handlers.clj | `lib/src/clojure_lsp/handlers.clj` | formatting 実装 |

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

```
api/format!
    |
    +-- internal-api/format!
            |
            +-- build-components
            |
            +-- format!*
                    |
                    +-- setup-api!
                    |
                    +-- dynamic-setup-project-analysis! (:project-namespaces-only)
                    |
                    +-- options->uris
                    |
                    +-- pmap (並列処理)
                            |
                            +-- open-file!
                            +-- handlers/formatting
                            +-- edit->summary
                    |
                    +-- apply-workspace-edit-summary! (dry? が false の場合)
```

### データフロー図

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

{:namespace [...]}       api/format!                         {:result-code 0/1
 :filenames [...]}       |                                    :message-fn fn
 :dry? boolean}          v                                    :edits [...]}
        |           options->uris                              |
        |                |                                     |
        +-------------> pmap で並列フォーマット                 |
                        |                                      |
                        v                                      |
                   handlers/formatting                         |
                        |                                      |
                        v                                      |
                   edit->summary                               |
                        |                                      |
              +---------+---------+                            |
              |                   |                            |
              v                   v                            |
        dry? = true         dry? = false                       |
              |                   |                            |
              v                   v                            |
        差分生成             ファイル更新 -------------------> 結果返却
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| api.clj | `lib/src/clojure_lsp/api.clj` | ソース | 公開 API 定義 |
| internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | ソース | 内部実装 |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | ハンドラー |
| format.clj | `lib/src/clojure_lsp/feature/format.clj` | ソース | フォーマット機能 |
| api_test.clj | `lib/test/clojure_lsp/api_test.clj` | テスト | API テスト |
