# 機能設計書 46-pnpm互換

## 概要

本ドキュメントは、Bunパッケージマネージャーのpnpm互換機能に関する設計書である。pnpm-lock.yamlからbun.lockbへの移行、pnpmワークスペース設定の読み込みについて詳述する。

### 本機能の処理概要

pnpm互換機能は、既存のpnpmプロジェクトからBunへのスムーズな移行を支援する機能である。pnpm-lock.yamlのパースとbun.lockbへの変換、pnpm-workspace.yamlの読み込みを行う。

**業務上の目的・背景**：pnpmは高速性とディスク効率に優れた人気のパッケージマネージャーである。多くの企業がpnpmを採用しているが、Bunへの移行を検討する際に既存のロックファイルを活用できることが重要である。pnpm互換機能により、pnpmプロジェクトをそのままBunで利用開始でき、移行コストを最小限に抑えられる。

**機能の利用シーン**：
- pnpmプロジェクトで初めて`bun install`を実行
- pnpm-lock.yamlが存在する環境でのBun導入
- pnpm-workspace.yamlを使用したmonorepoの移行

**主要な処理内容**：
1. pnpm-lock.yamlの存在確認
2. YAMLのパースとロックファイル構造の解析
3. 依存関係情報の抽出とBun形式への変換
4. ワークスペース設定（pnpm-workspace.yaml）の読み込み
5. overrides、patchedDependencies等の設定移行
6. bun.lockbの生成

**関連システム・外部連携**：
- pnpm-lock.yaml（入力）
- pnpm-workspace.yaml（入力）
- bun.lockb（出力）
- package.json

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | install | 主機能 | pnpm-lock.yamlからの移行 |

## 機能種別

データ変換（ロックファイル移行）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pnpm_lockfile | file | Yes | pnpm-lock.yaml | 有効なYAML形式 |
| lockfile_version | number | Yes | ロックファイルバージョン | 7以上 |
| workspace_yaml | file | No | pnpm-workspace.yaml | 有効なYAML形式 |

### 入力データソース

- pnpm-lock.yaml
- pnpm-workspace.yaml
- package.json

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| lockfile | Lockfile | 変換されたBunロックファイル |
| packages | array | パッケージ情報の配列 |
| workspace_paths | map | ワークスペースパス情報 |
| workspace_versions | map | ワークスペースバージョン情報 |

### 出力先

- bun.lockb（バイナリロックファイル）
- メモリ内Lockfile構造

## 処理フロー

### 処理シーケンス

```
1. ファイル検出
   └─ pnpm-lock.yamlの存在確認
2. YAML パース
   └─ lockfileVersionの確認（7以上が必要）
3. 構造解析
   └─ importers、packages、snapshotsの解析
4. パッケージ変換
   └─ 各パッケージをBun形式に変換
5. ワークスペース処理
   └─ workspace_paths、workspace_versionsの構築
6. 設定移行
   └─ overrides、catalogs、patchedDependenciesの変換
7. ロックファイル生成
   └─ bun.lockbの書き出し
```

### フローチャート

```mermaid
flowchart TD
    A[bun install開始] --> B{pnpm-lock.yaml存在?}
    B -->|No| C[通常インストール]
    B -->|Yes| D[YAMLパース]
    D --> E{lockfileVersion >= 7?}
    E -->|No| F[エラー: バージョン非対応]
    E -->|Yes| G[importersセクション解析]
    G --> H[packagesセクション解析]
    H --> I[snapshotsセクション解析]
    I --> J{pnpm-workspace.yaml存在?}
    J -->|Yes| K[ワークスペース設定読み込み]
    J -->|No| L[パッケージ変換]
    K --> L
    L --> M[overrides変換]
    M --> N[catalogs変換]
    N --> O[patchedDependencies変換]
    O --> P[bun.lockb生成]
    P --> Q[終了]
    C --> Q
    F --> Q
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-46-01 | バージョン要件 | lockfileVersion 7以上が必要 | 移行時 |
| BR-46-02 | 自動移行 | pnpm-lock.yaml検出時に自動変換 | bun install実行時 |
| BR-46-03 | ワークスペース継承 | pnpm-workspace.yamlをそのまま使用可能 | ワークスペース設定時 |
| BR-46-04 | overrides継承 | pnpmのoverridesをBun形式に変換 | overrides設定時 |
| BR-46-05 | パッチ継承 | patchedDependenciesをそのまま移行 | パッチ使用時 |

### 計算ロジック

依存パス解析（pnpm形式）:
```
// name@version(hash) -> name@version
removeSuffix(path) =
    if path ends with '(' && ')':
        return path[0..indexOfSuffix]
    else:
        return path
```

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

本機能はデータベースを使用しない。

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| PnpmLockfileTooOld | バージョンエラー | lockfileVersion < 7 | pnpmを更新してロックファイルを再生成 |
| PnpmLockfileVersionInvalid | 形式エラー | lockfileVersionが不正 | ロックファイルを再生成 |
| InvalidPnpmLockfile | 形式エラー | YAMLパースエラー | ロックファイルを確認 |
| YamlParseError | パースエラー | YAML構文エラー | YAML構文を修正 |
| PnpmLockfileNotObject | 型エラー | ルートがオブジェクトでない | ロックファイルを再生成 |
| PnpmLockfileMissingVersion | 必須フィールド欠如 | lockfileVersionがない | ロックファイルを再生成 |
| PnpmLockfileMissingImporters | 必須フィールド欠如 | importersがない | ロックファイルを再生成 |
| WorkspaceNameMissing | 名前欠如 | ワークスペースにnameがない | package.jsonにnameを追加 |
| NonExistentWorkspaceDependency | 依存エラー | 存在しないワークスペース依存 | 依存関係を確認 |
| DependencyLoop | 循環依存 | 循環的な依存関係 | 依存関係を見直し |

### リトライ仕様

YAMLパースエラーは自動リトライしない。手動での修正を促す。

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

移行処理はアトミック。失敗時はbun.lockbを生成しない。

## パフォーマンス要件

- YAMLパース: 1秒以内（10,000パッケージまで）
- 変換処理: 500ms以内（通常規模）
- メモリ使用: O(n)（パッケージ数に比例）

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

- integrity（SRI）ハッシュの維持
- 悪意のあるYAML（YAML bomb）への対策
- パス traversal への対策

## 備考

- pnpm lockfileVersion 7以降に対応
- catalogs機能をサポート
- pnpm-workspace.yamlとpackage.json workspaces両対応

---

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

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

### 推奨読解順序

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

pnpmロックファイル移行で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | pnpm.zig | `src/install/pnpm.zig` | MigratePnpmLockfileError型 |
| 1-2 | lockfile.zig | `src/install/lockfile.zig` | Lockfile構造体 |

**読解のコツ**: MigratePnpmLockfileErrorのバリアントを見ると対応するエラーケースが分かる。

#### Step 2: 移行処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | pnpm.zig | `src/install/pnpm.zig` | migratePnpmLockfile関数 |

**主要処理フロー**:
- **49-71行目**: MigratePnpmLockfileError で発生しうるエラーを定義
- **73-80行目**: migratePnpmLockfile関数のシグネチャ
- **91-134行目**: lockfileVersionの検証（7以上が必要）

#### Step 3: セクション解析を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | pnpm.zig | `src/install/pnpm.zig` | importers、catalogs、overridesの解析 |

**主要処理フロー**:
- **142-144行目**: catalogsセクションの解析
- **146-185行目**: overridesセクションの解析
- **196-222行目**: patchedDependenciesセクションの解析
- **224-278行目**: importersセクションの解析

#### Step 4: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | pnpm.zig | `src/install/pnpm.zig` | indexOfDepPathSuffix、removeSuffix |

**主要処理フロー**:
- **1-34行目**: indexOfDepPathSuffix関数でpnpm形式のパスサフィックスを検出
- **36-47行目**: removeSuffix関数でname@version形式に正規化

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

```
PackageManager
    │
    └─ migratePnpmLockfile()
           │
           ├─ YAML.parse()
           │      └─ pnpm-lock.yamlをパース
           │
           ├─ lockfileVersion検証
           │      └─ バージョン7以上を確認
           │
           ├─ Lockfile.CatalogMap.fromPnpmLockfile()
           │      └─ catalogsを変換
           │
           ├─ overrides解析
           │      └─ Dependency.parseで依存関係を解析
           │
           ├─ patchedDependencies解析
           │      └─ パッチ情報を抽出
           │
           ├─ importers解析
           │      └─ ワークスペース情報を構築
           │
           └─ packages/snapshots解析
                  └─ 全パッケージを変換
```

### データフロー図

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

pnpm-lock.yaml ─────────▶ YAML.parse() ────────────▶ YAMLオブジェクト
                              │
                              ▼
                      lockfileVersion確認 ──────────▶ バリデーション結果
                              │
                              ▼
pnpm-workspace.yaml ───▶ ワークスペース解析 ──────────▶ workspace_paths
(オプション)                   │
                              ▼
                      catalogs解析 ─────────────▶ CatalogMap
                              │
                              ▼
                      overrides解析 ────────────▶ overrides map
                              │
                              ▼
                      packages解析 ─────────────▶ Lockfile.Package[]
                              │
                              ▼
                      Lockfile生成 ─────────────▶ bun.lockb
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| pnpm.zig | `src/install/pnpm.zig` | ソース | pnpmロックファイル移行の中核 |
| lockfile.zig | `src/install/lockfile.zig` | ソース | Lockfile構造体定義 |
| PackageManager.zig | `src/install/PackageManager.zig` | ソース | 移行処理の呼び出し |
| yaml.zig | `src/yaml.zig` | ソース | YAMLパーサー |
| dependency.zig | `src/install/dependency.zig` | ソース | 依存関係解析 |
| semver.zig | `src/semver.zig` | ソース | セマンティックバージョン処理 |
