# 機能設計書 24-bun patch-commit

## 概要

本ドキュメントは、Bunパッケージマネージャーの `bun patch --commit` コマンドの機能設計を記述する。このコマンドは、`bun patch` で編集したパッケージの変更をパッチファイルとして保存する。

### 本機能の処理概要

`bun patch --commit` は、node_modules内で編集されたパッケージとオリジナルのキャッシュ版を比較し、差分をパッチファイル（.patch形式）として保存する機能を提供する。保存されたパッチは以降の `bun install` 時に自動的に適用される。

**業務上の目的・背景**：`bun patch` でパッケージを編集した後、その変更を永続化する必要がある。パッチファイルとして保存することで、チームメンバー間で変更を共有でき、`bun install` のたびに自動的にパッチが適用される。これにより、依存パッケージの修正をバージョン管理システムで追跡可能にする。

**機能の利用シーン**：
- `bun patch` で編集したパッケージの変更を保存する場合
- パッチファイルをGitリポジトリにコミットしてチームで共有する場合
- CI/CDパイプラインで再現可能なビルドを行う場合

**主要な処理内容**：
1. 引数の解析（編集したパッケージのパス または パッケージ名@バージョン）
2. lockfileの読み込みとパッケージ情報の取得
3. オリジナルキャッシュとの差分をgit diffで計算
4. パッチファイルをpatchesディレクトリに保存
5. package.jsonのpatchedDependenciesを更新
6. `bun install` を実行してパッチを適用

**関連システム・外部連携**：
- gitコマンド（差分計算に使用）
- ローカルファイルシステム

**権限による制御**：package.jsonとpatchesディレクトリへの書き込み権限が必要。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 16 | patch-commit | 主画面 | パッチファイルの生成とコミット |

## 機能種別

データ連携（ファイルシステム操作）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| --commit | flag | Yes | パッチをコミットするフラグ | - |
| path | string | Yes | 編集したパッケージのパス（例: node_modules/is-even）またはパッケージ名@バージョン | 存在確認 |
| --patches-dir | string | No | パッチファイルの保存先ディレクトリ（デフォルト: patches） | - |

### 入力データソース

- bun.lockb / bun.lock（lockfile）
- 編集されたパッケージディレクトリ
- グローバルキャッシュ（オリジナルパッケージ）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| パッチファイル | file | `patches/{package-name}@{version}.patch` |
| package.json更新 | file | patchedDependencies に追加 |
| 成功メッセージ | string | パッチファイルのパスを表示 |

### 出力先

- patchesディレクトリ（パッチファイル）
- package.json（patchedDependencies更新）
- 標準出力（コンソール）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の解析
   └─ --commitフラグと対象パスを取得
2. lockfileの読み込み
   └─ bun.lock または bun.lockb を読み込み
3. パッケージ情報の取得
   ├─ パス指定時: package.jsonからパッケージ名・バージョンを取得
   └─ 名前指定時: lockfileからパッケージIDを検索
4. キャッシュディレクトリの特定
   └─ computeCacheDirAndSubpathでオリジナルの場所を取得
5. 一時ディレクトリの準備
   └─ 差分計算用の一時ディレクトリ
6. git diffの実行
   └─ オリジナル(キャッシュ)と変更後(node_modules)を比較
7. 差分の後処理
   └─ パスの正規化などの調整
8. パッチファイルの保存
   ├─ patchesディレクトリの作成
   └─ {package}@{version}.patchとして保存
9. package.jsonの更新
   └─ patchedDependenciesにエントリを追加
10. bun installの実行
    └─ パッチを適用してパッケージを再インストール
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数解析]
    B --> C[lockfile読み込み]
    C --> D{lockfile存在?}
    D -->|No| E[エラー: lockfile必須]
    D -->|Yes| F[パッケージ情報取得]
    F --> G[キャッシュパス計算]
    G --> H{git使用可能?}
    H -->|No| I[エラー: git必須]
    H -->|Yes| J[nested node_modules退避]
    J --> K[git diff実行]
    K --> L{差分あり?}
    L -->|No| M[変更なしメッセージ]
    L -->|Yes| N[差分後処理]
    N --> O[patchesディレクトリ作成]
    O --> P[パッチファイル保存]
    P --> Q[package.json更新]
    Q --> R[bun install実行]
    R --> S[完了]
    M --> S
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-24-01 | lockfile必須 | lockfileが存在する必要がある | 常時 |
| BR-24-02 | git必須 | gitコマンドが使用可能である必要がある | 常時 |
| BR-24-03 | パッチファイル命名 | `{package}@{version}.patch` 形式で保存 | 常時 |
| BR-24-04 | nested除外 | node_modules/.git等はパッチから除外 | 常時 |
| BR-24-05 | 変更なし許容 | 差分がない場合はエラーとせずメッセージ表示 | 常時 |

### 計算ロジック

**パッチファイル名のエスケープ**:
```
"/" -> "%2F"
"\\" -> "%5c"
" " -> "%20"
"\n" -> "%0A"
"\r" -> "%0D"
"\t" -> "%09"
```

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

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

本機能はデータベースを使用しない。ファイルシステムのみを操作する。

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | LockfileNotFound | lockfileが見つからない | bun installを実行 |
| - | GitNotFound | gitコマンドが見つからない | gitをインストール |
| - | DiffFailed | git diff実行失敗 | git環境を確認 |
| - | WriteError | パッチファイル書き込み失敗 | 権限を確認 |

### リトライ仕様

リトライ処理は実装されていない。

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

トランザクション管理なし。処理が途中で失敗した場合、部分的に更新された状態になる可能性がある（パッチファイルは作成されたがpackage.jsonは未更新等）。

## パフォーマンス要件

パッケージサイズと変更量に依存。一般的なパッケージで数秒から数十秒程度。

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

- パッチファイルにはソースコードの差分が含まれる
- 機密情報が含まれないよう注意が必要
- パッチファイルはGitリポジトリにコミットされることを想定

## 備考

- pnpm patch-commit / yarn patch-commit との互換性を意識
- パッチファイルはUnified diff形式
- `.bun-patch-tag` ファイルは処理後に削除される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | patchPackage.zig | `src/install/PackageManager/patchPackage.zig` | PatchCommitResult構造体（1-5行目）で結果を定義 |

**読解のコツ**: 戻り値の構造体からコマンドの出力内容を理解する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | patch_commit_command.zig | `src/cli/patch_commit_command.zig` | exec関数がupdatePackageJSONAndInstallCatchErrorを呼び出し |
| 2-2 | patchPackage.zig | `src/install/PackageManager/patchPackage.zig` | doPatchCommit関数（12行目〜）がメイン処理 |

**主要処理フロー**:
1. **16-53行目**: lockfileの読み込みとエラー処理
2. **55-69行目**: 引数の取得とパス調整
3. **72-83行目**: node_modulesディレクトリのオープン
4. **85-181行目**: 引数形式に応じたパッケージ情報とキャッシュパスの取得
5. **192-391行目**: git diffによる差分計算
6. **394-456行目**: パッチファイルの保存とディレクトリ作成

#### Step 3: git diff処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | patchPackage.zig | `src/install/PackageManager/patchPackage.zig` | 310-391行目のgit diff呼び出し |

**主要処理フロー**:
- **220-236行目**: nested node_modulesの一時退避
- **243-273行目**: .bun-patch-tagの一時退避
- **311-329行目**: gitコマンドの検出
- **330-331行目**: gitDiffPreprocessPathsでパス準備
- **333-348行目**: git diff --no-indexの実行
- **350-381行目**: diffPostProcessで出力を整形

#### Step 4: パッチファイル保存を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | patchPackage.zig | `src/install/PackageManager/patchPackage.zig` | 394-456行目のファイル書き込み |

**主要処理フロー**:
- **395-409行目**: 一時ファイルへの書き込み
- **417-423行目**: ファイル名のエスケープ処理
- **426-432行目**: パッチファイルパスの構築
- **434-441行目**: patchesディレクトリの作成
- **443-453行目**: 一時ファイルのリネーム

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

```
PatchCommitCommand.exec
    │
    └─ updatePackageJSONAndInstallCatchError
           │
           └─ doPatchCommit
                  ├─ Lockfile.loadFromCwd
                  ├─ PatchArgKind.fromArg
                  ├─ pkgInfoForNameAndVersion (名前指定時)
                  ├─ computeCacheDirAndSubpath
                  ├─ bun.patch.gitDiffPreprocessPaths
                  ├─ bun.spawnSync (git diff)
                  ├─ bun.patch.diffPostProcess
                  ├─ nodefs.mkdirRecursive
                  └─ bun.sys.renameatConcurrently
```

### データフロー図

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

パッケージパス ───▶ パッケージ情報取得
     │                  │
     ▼                  ▼
lockfile ──────▶ キャッシュパス計算 ───▶ オリジナルパス
                       │
                       ▼
キャッシュ       ◀── git diff ───▶ 差分データ
(オリジナル)           │
                       ▼
              差分後処理 ───▶ パッチ内容
                       │
                       ▼
patchesディレクトリ ◀── ファイル保存 ───▶ .patchファイル
                       │
                       ▼
package.json ◀─── patchedDependencies更新
                       │
                       ▼
              bun install ───▶ パッチ適用
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| patch_commit_command.zig | `src/cli/patch_commit_command.zig` | ソース | patch-commitコマンドのエントリーポイント |
| patchPackage.zig | `src/install/PackageManager/patchPackage.zig` | ソース | パッチコミット処理の実装 |
| lockfile.zig | `src/install/lockfile.zig` | ソース | lockfileの読み込み |
| patch.zig | `src/patch.zig` | ソース | git diff処理のユーティリティ |
| PackageManager.zig | `src/install/PackageManager.zig` | ソース | パッケージ管理の中核 |
