# 帳票設計書 3-clean-ns

## 概要

本ドキュメントは、clojure-lspのclean-ns（名前空間整理）機能によって出力される帳票の設計仕様を定義する。

### 本帳票の処理概要

clean-ns帳票は、名前空間（ns）フォームの整理結果を出力する帳票である。未使用のrequires/refers/importsを検出し、アルファベット順にソートした差分をunified diff形式で表示する。`--dry`オプションで変更を適用せずに差分のみを確認することが可能である。

**業務上の目的・背景**：Clojureプロジェクトの開発において、名前空間のrequire/import文は時間とともに肥大化し、未使用の依存が蓄積される傾向がある。本帳票は、コードベースの健全性を維持し、不要な依存を除去することで、コンパイル時間の短縮、メモリ使用量の削減、コードの可読性向上を目的とする。また、チーム内でのコーディングスタイル統一にも貢献する。

**帳票の利用シーン**：本帳票は以下の場面で利用される。(1) コードレビュー前の自動クリーンアップ、(2) CI/CDパイプラインでの整形チェック（dryモード）、(3) リファクタリング後の依存整理、(4) プロジェクト全体の一括クリーンアップ、(5) 新規メンバーのオンボーディング時のコード標準化。

**主要な出力内容**：
1. 未使用require/refer/importの検出結果
2. アルファベット順ソート後の差分
3. unified diff形式での変更内容表示
4. 変更対象ファイルのリスト
5. 変更件数のサマリー

**帳票の出力タイミング**：CLIコマンド`clojure-lsp clean-ns`の実行時、またはAPI経由での`clojure-lsp.api/clean-ns!`関数呼び出し時に出力される。`--dry`オプション指定時は差分表示のみ、未指定時はファイル変更も実行される。

**帳票の利用者**：開発者、コードレビュアー、CI/CDシステム、テックリード

## 帳票種別

差分レポート / 整理結果レポート

## 利用画面

| 画面No | 画面名 | URL/ルーティング | 出力操作 |
|--------|--------|-----------------|---------|
| CLI-01 | コマンドライン | `clojure-lsp clean-ns` | コマンド実行 |
| CLI-02 | コマンドライン（ドライラン） | `clojure-lsp clean-ns --dry` | コマンド実行 |
| API-01 | Clojure REPL | `(clojure-lsp.api/clean-ns! opts)` | 関数呼び出し |

## 出力形式

### 基本仕様

| 項目 | 内容 |
|-----|------|
| ファイル形式 | unified diff（テキスト） |
| 用紙サイズ | N/A（コンソール出力） |
| 向き | N/A |
| ファイル名 | 標準出力 |
| 出力方法 | 標準出力 / 標準エラー出力 |
| 文字コード | UTF-8 |

### 出力フォーマット詳細

#### unified diff形式
```diff
--- a/src/my_project/core.clj
+++ b/src/my_project/core.clj
@@ -1,8 +1,6 @@
 (ns my-project.core
   (:require
-   [clojure.string :as str]
-   [unused.namespace :as unused]
+   [clojure.string :as str]
    [used.namespace :as used]))
```

#### 実行モード別出力

**dryモード（`--dry`）**:
- 差分のみ表示、ファイル変更なし
- result-code: 1（変更あり）、0（変更なし）

**実行モード（デフォルト）**:
- ファイル変更を実行
- 変更した名前空間をログ出力
- result-code: 0

## 帳票レイアウト

### レイアウト概要

unified diff形式で差分を出力。各ファイルごとにヘッダーと変更内容が表示される。

```
┌─────────────────────────────────────────────────────────────────┐
│  --- a/src/namespace/file.clj                                   │
│  +++ b/src/namespace/file.clj                                   │
│  @@ -1,10 +1,8 @@                                               │
│   (ns namespace.file                                             │
│     (:require                                                    │
│  -   [unused.ns :as unused]                                      │
│  +   [used.ns :as used]))                                        │
└─────────────────────────────────────────────────────────────────┘
```

### 出力項目

| No | 項目名 | 説明 | データ取得元 | 表示形式 |
|----|-------|------|-------------|---------|
| 1 | 旧ファイルパス | 変更前ファイル | URI | `--- a/path` |
| 2 | 新ファイルパス | 変更後ファイル | URI | `+++ b/path` |
| 3 | 変更範囲 | 行番号範囲 | range | `@@ -n,m +n,m @@` |
| 4 | 削除行 | 削除されるコード | old-text | `-` プレフィックス |
| 5 | 追加行 | 追加されるコード | new-text | `+` プレフィックス |
| 6 | コンテキスト行 | 変更なし行 | - | スペースプレフィックス |

## 出力条件

### 抽出条件

| 条件名 | 説明 | 必須 |
|-------|------|-----|
| project-root | プロジェクトルートディレクトリ | No（デフォルト: カレントディレクトリ） |
| namespace | 対象名前空間（複数指定可） | No（デフォルト: 全名前空間） |
| filenames | 対象ファイル（複数指定可） | No |
| ns-exclude-regex | 除外名前空間の正規表現 | No |
| dry? | ドライランモード | No（デフォルト: false） |

### 整理対象

| 対象 | 説明 | 設定キー |
|------|------|---------|
| 未使用require | 使用されていないrequire | - |
| 未使用refer | 使用されていないrefer | - |
| 未使用import | 使用されていないimport | - |
| 重複require | 同一名前空間の重複require | - |
| ソート | アルファベット順整列 | `:clean :sort` |

### ソート順

| 優先度 | 項目 | 昇順/降順 |
|-------|------|---------|
| 1 | require/import | 設定による（デフォルト: 昇順） |
| 2 | refer | 設定による（デフォルト: 昇順） |

### 改ページ条件

N/A（コンソール出力のため）

## データベース参照仕様

### 参照テーブル一覧

| テーブル名 | 用途 | 結合条件 |
|-----------|------|---------|
| db.analysis | 解析データ | URI |
| db.documents | ドキュメントテキスト | URI |

### 解析データ詳細

| 参照項目 | 帳票項目との対応 | 取得条件 | 備考 |
|---------|----------------|---------|------|
| namespace-usages | 使用中の名前空間 | URI単位 | requireの使用判定 |
| var-usages | 使用中の変数 | URI単位 | referの使用判定 |
| java-class-usages | 使用中のJavaクラス | URI単位 | importの使用判定 |

## 計算仕様

### 計算項目一覧

| 項目名 | 計算式 | 端数処理 | 備考 |
|-------|-------|---------|------|
| result-code (dry) | edits存在 ? 1 : 0 | - | dryモード |
| result-code (exec) | 常に0 | - | 実行モード |
| unused-aliases | 解析データから未使用エイリアス抽出 | - | q/find-unused-aliases |
| unused-refers | 解析データから未使用refer抽出 | - | q/find-unused-refers |
| unused-imports | 解析データから未使用import抽出 | - | q/find-unused-imports |

## 処理フロー

### 出力フロー

```mermaid
flowchart TD
    A[clean-nsコマンド実行] --> B[オプション解析]
    B --> C[プロジェクト解析初期化]
    C --> D[対象URI取得]
    D --> E[各URIのドキュメント読込]
    E --> F[clean-ns実行コマンド呼出]
    F --> G[未使用要素検出]
    G --> H[ソート処理]
    H --> I[編集内容生成]
    I --> J{dry?}
    J -->|Yes| K[差分文字列生成]
    J -->|No| L[ファイル変更適用]
    K --> M[差分出力]
    L --> N[変更ログ出力]
    M --> O[終了コード設定]
    N --> O
    O --> P[終了]
```

## エラー処理

### エラーケース一覧

| エラー種別 | 発生条件 | 表示メッセージ | 対処方法 |
|----------|---------|--------------|---------|
| プロジェクト解析失敗 | 不正なプロジェクト構成 | Error during project analysis | プロジェクト設定確認 |
| 名前空間未発見 | 指定名前空間が存在しない | Namespace X not found | 名前空間名確認 |
| 変更なし | 整理不要 | Nothing to clear! | 正常終了 |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定データ件数 | 数百〜数千ファイル |
| 目標出力時間 | 1ファイルあたり: 100ms以内 |
| 同時出力数上限 | 並列処理（pmap使用） |

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

- ファイル変更を伴うため、バージョン管理システムでの差分確認を推奨
- `--dry`オプションでの事前確認を推奨

## 備考

- `:clean :sort`設定でソート動作をカスタマイズ可能
- `:clean :ns-inner-blocks-indentation`でインデントスタイルを設定可能
- リーダーコンディショナル（`#?`）内の要素も適切に処理される

---

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

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

### 推奨読解順序

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

clean-ns機能で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | **433-459行目**: `clean-ns-edits`関数の戻り値構造 |
| 1-2 | queries.clj | `lib/src/clojure_lsp/queries.clj` | 未使用要素検出関数群 |

**読解のコツ**: clean-nsは`zloc`（rewrite-cljのzipper）を操作してns formを変換する。zlocベースの編集操作を理解することが重要。

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

CLIからの呼び出しフローを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.clj | `cli/src/clojure_lsp/main.clj` | **176行目**: `"clean-ns"`アクション分岐 |
| 2-2 | main.clj | `cli/src/clojure_lsp/main.clj` | **202行目**: `internal-api/clean-ns!`呼び出し |

**主要処理フロー**:
1. **156-180行目**: `parse`関数でコマンドライン引数を解析
2. **194-215行目**: `handle-action!`関数でアクション実行
3. **202行目**: clean-nsの場合`internal-api/clean-ns!`を呼び出し

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | **296-323行目**: `clean-ns!*`関数の実装 |
| 3-2 | internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | **243-251行目**: `edits->diff-string`関数 |

**主要処理フロー**:
- **298行目**: `setup-project-only-analysis!`でプロジェクト解析
- **301-308行目**: 各URIに対してclean-nsコマンド実行
- **310-323行目**: dry/実行モードに応じた処理

#### Step 4: clean-ns機能コア層を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | **433-459行目**: `clean-ns-edits`メイン関数 |
| 4-2 | clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | **299-308行目**: `clean-requires`関数 |
| 4-3 | clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | **398-407行目**: `clean-imports`関数 |
| 4-4 | clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | **50-141行目**: `process-clean-ns`関数 |

**主要処理フロー**:
- **439-443行目**: 未使用要素の検出（future使用で並列実行）
- **453-456行目**: requires整理 → imports整理 → ns children ソート
- **457-458行目**: 編集結果の構築

#### Step 5: diff生成を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | diff.clj | `lib/src/clojure_lsp/diff.clj` | **20-34行目**: `unified-diff`関数 |
| 5-2 | diff.clj | `lib/src/clojure_lsp/diff.clj` | **47-55行目**: `colorize-diff`関数 |

**主要処理フロー**:
- **25-33行目**: DiffUtils.generateUnifiedDiffでunified diff生成
- **47-55行目**: ANSI色付け処理

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

```
clojure-lsp.main/-main
    |
    +-- parse (コマンド解析)
    |
    +-- handle-action!
           |
           +-- clojure-lsp.internal-api/clean-ns!
                  |
                  +-- build-components (コンポーネント初期化)
                  |
                  +-- clean-ns!*
                         |
                         +-- setup-api!
                         |
                         +-- setup-project-only-analysis!
                         |
                         +-- options->uris
                         |
                         +-- [pmap] open-file! + handlers/execute-command
                         |              |
                         |              +-- f.command/clean-ns
                         |                     |
                         |                     +-- f.clean-ns/clean-ns-edits
                         |                            |
                         |                            +-- q/find-unused-aliases
                         |                            +-- q/find-unused-refers
                         |                            +-- q/find-unused-imports
                         |                            +-- q/find-duplicate-requires
                         |                            |
                         |                            +-- clean-requires
                         |                            +-- clean-imports
                         |                            +-- sort-ns-children
                         |
                         +-- document-change->edit-summary
                         |
                         +-- [dry?] edits->diff-string
                         |             |
                         |             +-- diff/unified-diff
                         |             +-- diff/colorize-diff
                         |
                         +-- [!dry?] apply-workspace-edit-summary!
```

### データフロー図

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

CLIオプション ────────▶ parse ────────────────────────▶ options map
     |                                                      |
     v                                                      v
project-root ─────────▶ analyze! ─────────────────────▶ db (analysis)
     |                                                      |
     v                                                      v
namespace/filenames ──▶ options->uris ────────────────▶ [uri ...]
     |                                                      |
     v                                                      v
uri ──────────────────▶ open-file! ───────────────────▶ db.documents[uri]
     |                                                      |
     v                                                      v
db.analysis ──────────▶ find-unused-* ────────────────▶ clean-ctx
     |                                                      |
     v                                                      v
ns-loc (zloc) ────────▶ clean-requires/imports ───────▶ result-loc
     |                                                      |
     v                                                      v
edit-summary ─────────▶ unified-diff ─────────────────▶ diff string
                                                            |
                                                            v
                       colorize-diff ─────────────────▶ stdout
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| main.clj | `cli/src/clojure_lsp/main.clj` | ソース | CLIエントリーポイント |
| api.clj | `lib/src/clojure_lsp/api.clj` | ソース | 公開API定義 |
| internal_api.clj | `lib/src/clojure_lsp/internal_api.clj` | ソース | 内部API実装 |
| clean_ns.clj | `lib/src/clojure_lsp/feature/clean_ns.clj` | ソース | clean-ns機能コア |
| command.clj | `lib/src/clojure_lsp/feature/command.clj` | ソース | コマンド実行 |
| handlers.clj | `lib/src/clojure_lsp/handlers.clj` | ソース | LSPハンドラ |
| queries.clj | `lib/src/clojure_lsp/queries.clj` | ソース | 解析クエリ |
| diff.clj | `lib/src/clojure_lsp/diff.clj` | ソース | diff生成 |
| edit.clj | `lib/src/clojure_lsp/refactor/edit.clj` | ソース | 編集ユーティリティ |
| settings.clj | `lib/src/clojure_lsp/settings.clj` | ソース | 設定管理 |
| clean_ns_test.clj | `lib/test/clojure_lsp/feature/clean_ns_test.clj` | テスト | clean-ns機能テスト |
