# 機能設計書 21-bun unlink

## 概要

本ドキュメントは、Bunパッケージマネージャーの `bun unlink` コマンドの機能設計を記述する。このコマンドは、`bun link` で作成したグローバルパッケージリンクを解除するために使用される。

### 本機能の処理概要

`bun unlink` は、ローカルで開発中のnpmパッケージをグローバルリンクディレクトリから削除し、他のプロジェクトからの参照を解除する機能を提供する。

**業務上の目的・背景**：パッケージ開発時に `bun link` でグローバルにリンクしたパッケージを、開発完了後やテスト終了後に削除する必要がある。リンクを放置すると意図しないバージョンのパッケージが参照され続けるリスクがある。この機能により、開発環境をクリーンな状態に戻すことができる。

**機能の利用シーン**：
- ローカルパッケージ開発の完了後、グローバルリンクを削除したい場合
- リンクしたパッケージが不要になり、ディスクスペースを解放したい場合
- 別バージョンのパッケージをリンクする前に既存リンクを解除したい場合

**主要な処理内容**：
1. カレントディレクトリのpackage.jsonを解析してパッケージ名を取得
2. グローバルリンクディレクトリにリンクが存在するか確認
3. パッケージにバイナリ（bin）が定義されている場合、グローバルbinディレクトリからバイナリリンクを削除
4. グローバルnode_modulesからパッケージディレクトリを削除

**関連システム・外部連携**：ローカルファイルシステムのみを操作。外部APIとの連携はない。

**権限による制御**：グローバルディレクトリへの書き込み権限が必要。Windows環境では管理者権限が必要な場合がある。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 13 | unlink | 主画面 | リンクしたパッケージの登録解除 |

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| (なし) | - | - | 引数なしでカレントパッケージをunlink | package.jsonにname属性が必要 |

### 入力データソース

- カレントディレクトリのpackage.jsonファイル
- bunfig.toml（グローバルディレクトリ設定）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 成功メッセージ | string | `success: unlinked package "{パッケージ名}"` |
| 情報メッセージ | string | パッケージが既にリンクされていない場合 |
| エラーメッセージ | string | エラー発生時のメッセージ |

### 出力先

標準出力（コンソール）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の解析
   └─ PackageManager.CommandLineArguments.parseで.unlinkとして解析
2. パッケージマネージャーの初期化
   └─ PackageManager.initでコンテキストを設定
3. package.jsonの解析
   └─ パッケージ名を取得、name属性必須
4. パッケージ名のバリデーション
   └─ NPMパッケージ名として有効か検証
5. グローバルリンクの存在確認
   └─ Syscall.lstatでシンボリックリンクか確認
6. グローバルディレクトリのセットアップ
   └─ Options.openGlobalDirでグローバルディレクトリを開く
7. バイナリリンクの解除
   └─ Bin.Linker.unlinkで実行ファイルリンクを削除
8. パッケージディレクトリの削除
   └─ node_modules.deleteTreeでパッケージを削除
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[引数解析]
    B --> C[PackageManager初期化]
    C --> D{package.json存在?}
    D -->|No| E[package.json作成試行]
    D -->|Yes| F[package.json解析]
    E --> F
    F --> G{name属性あり?}
    G -->|No| H[エラー出力・終了]
    G -->|Yes| I{有効なNPM名?}
    I -->|No| H
    I -->|Yes| J{グローバルリンク存在?}
    J -->|No| K[リンクなしメッセージ出力]
    J -->|Yes| L[グローバルディレクトリ設定]
    K --> M[正常終了]
    L --> N{bin定義あり?}
    N -->|Yes| O[バイナリリンク解除]
    N -->|No| P[パッケージディレクトリ削除]
    O --> P
    P --> Q[成功メッセージ出力]
    Q --> M
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-21-01 | パッケージ名必須 | package.jsonにname属性が必要 | 常時 |
| BR-21-02 | 有効なNPM名 | パッケージ名はNPM命名規則に準拠 | 常時 |
| BR-21-03 | リンク確認 | リンクが存在しない場合はエラーとしない | 常時 |

### 計算ロジック

計算ロジックは存在しない。

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

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | MissingPackageJSON | package.jsonが見つからない | bun initで初期化 |
| - | InvalidPackageName | パッケージ名が無効 | package.jsonのname属性を修正 |
| - | FileSystemError | ディレクトリ削除失敗 | 権限を確認 |

### リトライ仕様

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

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

トランザクション管理なし（ファイルシステム操作のため）。削除処理が途中で失敗した場合、部分的に削除された状態になる可能性がある。

## パフォーマンス要件

特別なパフォーマンス要件なし。通常は1秒以内に完了する。

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

- グローバルディレクトリへの書き込み権限が必要
- シンボリックリンクの追跡による意図しないファイル削除のリスクはlstat確認で軽減

## 備考

現在、`bun unlink {packageName}` 形式（特定パッケージ名を指定してunlink）は未実装。引数ありで実行するとエラーとなる。

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | lockfile.zig | `src/install/lockfile.zig` | Lockfile.Package構造体の定義、パッケージ情報の保持方法 |

**読解のコツ**: Zigの構造体定義を読む際、フィールドの型と初期化方法に注目する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | unlink_command.zig | `src/cli/unlink_command.zig` | コマンドのエントリーポイント |

**主要処理フロー**:
1. **2行目**: `exec`関数でunlink関数を呼び出し
2. **7-16行目**: PackageManager初期化、package.jsonがない場合は作成を試行
3. **24-56行目**: package.json解析とパッケージ名検証
4. **58-69行目**: グローバルリンクの存在確認
5. **71-87行目**: グローバルディレクトリのセットアップ
6. **90-118行目**: バイナリリンクの解除
7. **121-128行目**: パッケージディレクトリの削除と成功メッセージ出力

#### Step 3: パッケージマネージャー初期化を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | PackageManager.zig | `src/install/PackageManager.zig` | init関数の処理、CommandLineArgumentsの解析 |

#### Step 4: バイナリリンク処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Bin.zig | `src/install/Bin.zig` | Linker構造体のunlink関数、バイナリの削除処理 |

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

```
UnlinkCommand.exec
    │
    ├─ unlink
    │      ├─ PackageManager.CommandLineArguments.parse
    │      ├─ PackageManager.init
    │      ├─ package.parse (Lockfile.Package)
    │      ├─ Syscall.lstat (リンク確認)
    │      ├─ Options.openGlobalDir
    │      ├─ Bin.Linker.unlink
    │      └─ node_modules.deleteTree
    │
    └─ Output.prettyln (結果出力)
```

### データフロー図

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

package.json ───▶ パッケージ情報解析 ───▶ パッケージ名
                       │
グローバル       ◀─────┘
リンクディレクトリ
    │
    ▼
リンク存在確認 ───▶ 存在する場合
    │                  │
    ▼                  ▼
削除処理 ◀───────── バイナリリンク解除
    │
    ▼
成功/エラー ───────▶ 標準出力
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| unlink_command.zig | `src/cli/unlink_command.zig` | ソース | unlinkコマンドのエントリーポイント |
| PackageManager.zig | `src/install/PackageManager.zig` | ソース | パッケージマネージャーの初期化と設定 |
| lockfile.zig | `src/install/lockfile.zig` | ソース | パッケージ情報のパース |
| Bin.zig | `src/install/Bin.zig` | ソース | バイナリリンクの管理 |
| bunfig.zig | `src/bunfig.zig` | ソース | 設定ファイルの読み込み |
