# 機能設計書 31-プラグインローダー

## 概要

本ドキュメントは、Prettierのプラグインローダー機能について記述する。この機能は、外部プラグインを動的に読み込み、Prettierの言語サポートを拡張する役割を担う。

### 本機能の処理概要

プラグインローダーは、Prettierが対応していない言語やカスタムフォーマットルールを追加するためのプラグインを動的に読み込む機能である。npmパッケージとして公開されたプラグインや、ローカルファイルとして作成されたプラグインを読み込み、Prettierのパーサーおよびプリンターとして登録する。

**業務上の目的・背景**：Prettierは標準で多くの言語をサポートしているが、すべての言語やフォーマットルールを組み込みで提供することは現実的ではない。プラグインシステムを通じて、コミュニティや開発者が独自の言語サポートやフォーマットルールを追加できるようにすることで、Prettierの拡張性と柔軟性を確保している。これにより、PHP、Ruby、Javaなどの追加言語サポートや、組織固有のフォーマットルールを導入できる。

**機能の利用シーン**：
- npmパッケージとして公開されているPrettierプラグイン（例：prettier-plugin-php）をインストールして使用する場合
- プロジェクト固有のカスタムフォーマットルールをプラグインとして作成し、ローカルから読み込む場合
- エディタ統合でプラグインを含むフォーマットを実行する場合

**主要な処理内容**：
1. プラグイン指定の受け取り（文字列パス、URL、またはプラグインオブジェクト）
2. プラグインモジュールの動的インポート
3. プラグインのキャッシュ管理
4. ビルトインプラグインとの統合

**関連システム・外部連携**：Node.jsのモジュールシステム（ESM/CommonJS）、npmパッケージ管理システム

**権限による制御**：特になし。ファイルシステムへのアクセス権限はNode.jsの実行環境に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | Usage - Plugins | 主画面 | 外部プラグインの読み込み・使用方法を説明 |
| 17 | Usage - Browser | 参照画面 | ブラウザ環境でのプラグイン読み込みを説明 |

## 機能種別

データ連携 / プラグイン管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| plugins | Array<string \| URL \| object> | No | 読み込むプラグインの配列。文字列（パッケージ名またはファイルパス）、URL、またはプラグインオブジェクト | 配列であること |

### 入力データソース

- Prettier API呼び出し時のオプションとして指定
- CLI実行時の--pluginオプション
- 設定ファイル（prettierrc等）のpluginsプロパティ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| plugins | Array<Plugin> | 読み込まれたプラグインオブジェクトの配列 |

### 出力先

Prettier内部のプラグインレジストリ（formatWithCursor等のAPI内部で使用）

## 処理フロー

### 処理シーケンス

```
1. loadPlugins関数呼び出し
   └─ プラグイン配列を受け取る
2. 各プラグインに対してloadPlugin関数を実行
   └─ Promise.allで並列実行
3. loadPlugin関数内での処理分岐
   ├─ プラグインが文字列/URLでない場合 → そのまま返却
   └─ 文字列/URLの場合 → キャッシュ確認後、インポート実行
4. importPlugin関数でモジュール読み込み
   ├─ URLの場合 → 直接import()
   ├─ 絶対パスの場合 → pathToFileURLでURL化してimport()
   └─ 相対パス/パッケージ名の場合 → ローカル試行後、node_modulesから読み込み
5. プラグインオブジェクトの正規化
   └─ module.defaultまたはmodule自体をプラグインとして返却
```

### フローチャート

```mermaid
flowchart TD
    A[loadPlugins呼び出し] --> B{plugins配列をループ}
    B --> C[loadPlugin実行]
    C --> D{pluginの型は?}
    D -->|string/URL| E{キャッシュあり?}
    D -->|object| F[そのまま返却]
    E -->|Yes| G[キャッシュから返却]
    E -->|No| H[importPlugin実行]
    H --> I{URLか?}
    I -->|Yes| J[直接import]
    I -->|No| K{絶対パスか?}
    K -->|Yes| L[pathToFileURLでimport]
    K -->|No| M[ローカルファイル試行]
    M --> N{成功?}
    N -->|Yes| O[importしたモジュール返却]
    N -->|No| P[node_modulesから読み込み]
    J --> Q[モジュール正規化]
    L --> Q
    O --> Q
    P --> Q
    Q --> R[キャッシュに保存]
    R --> S[プラグイン返却]
    F --> S
    G --> S
    S --> T[全プラグイン統合]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-31-01 | キャッシュ優先 | 同一プラグインの再読み込み時はキャッシュを使用 | プラグインパスとcwdの組み合わせが一致する場合 |
| BR-31-02 | ローカル優先 | 相対パス指定時はローカルファイルを優先して試行 | パスが相対パスの場合 |
| BR-31-03 | デフォルトエクスポート優先 | ES Modulesのdefaultエクスポートを優先使用 | module.defaultが存在する場合 |

### 計算ロジック

キャッシュキーの生成：
```javascript
const cacheKey = JSON.stringify({ name: plugin, cwd });
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ModuleNotFoundError | 指定されたプラグインが見つからない場合 | プラグイン名/パスを確認し、インストール状況を確認 |
| - | SyntaxError | プラグインのJavaScriptコードに構文エラーがある場合 | プラグインのコードを修正 |

### リトライ仕様

リトライは行わない。エラー発生時は即座に例外をスロー。

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

本機能はトランザクション管理を必要としない。

## パフォーマンス要件

- キャッシュ機構により、同一プラグインの再読み込みを回避
- Promise.allによる並列読み込みで複数プラグインの読み込み時間を最適化

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

- プラグインは任意のJavaScriptコードを実行できるため、信頼できるソースからのみプラグインを読み込むこと
- URLからの直接読み込み時は、HTTPSを使用することを推奨

## 備考

- ブラウザ環境（スタンドアロンビルド）では、プラグインは明示的にバンドルに追加する必要がある
- clearCache関数でプラグインキャッシュをクリア可能

---

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

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

### 推奨読解順序

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

プラグインの型定義とインターフェースを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | utilities.js | `src/main/plugins/builtin-plugins/utilities.js` | PluginInformation型定義（1-10行目）でプラグインの構造を理解 |

**読解のコツ**: プラグインは`name`、`load`、`options`、`languages`、`parsers`、`printers`のプロパティを持つオブジェクトとして定義されている。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.js | `src/main/plugins/index.js` | プラグインシステムのエクスポート構造を確認 |
| 2-2 | load-plugins.js | `src/main/plugins/load-plugins.js` | loadPlugins関数がエントリーポイント |

**主要処理フロー**:
1. **3-5行目**: loadPlugins関数でプラグイン配列を受け取り、Promise.allで並列処理
2. **4行目**: 各プラグインに対してloadPlugin関数を呼び出し

#### Step 3: プラグイン読み込みロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | load-plugin.js | `src/main/plugins/load-plugin.js` | プラグインの動的インポートとキャッシュ管理 |

**主要処理フロー**:
- **10-27行目**: importPlugin関数でモジュールの動的インポート
- **33-39行目**: loadPluginWithoutCache関数でプラグインオブジェクトの正規化
- **41-55行目**: loadPlugin関数でキャッシュ確認とキャッシュへの保存
- **57-59行目**: clearCache関数でキャッシュクリア

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

```
loadPlugins (load-plugins.js:3)
    │
    └─ loadPlugin (load-plugin.js:42)
           │
           ├─ [キャッシュヒット] → キャッシュから返却
           │
           └─ [キャッシュミス] → loadPluginWithoutCache (load-plugin.js:33)
                  │
                  └─ importPlugin (load-plugin.js:10)
                         │
                         ├─ [URL] → import(url)
                         ├─ [絶対パス] → import(pathToFileURL(name).href)
                         └─ [相対パス/パッケージ名]
                                │
                                ├─ [ローカル成功] → import(pathToFileURL(path.resolve(name)).href)
                                └─ [ローカル失敗] → importFromDirectory(name, cwd)
```

### データフロー図

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

plugins配列              loadPlugins                    統合されたplugins配列
(string/URL/object) ───▶ Promise.all ───▶             (Plugin objects)
                              │
                              ▼
                         loadPlugin
                              │
                    ┌─────────┴─────────┐
                    │                   │
              [object]             [string/URL]
                 │                      │
                 │                 キャッシュ確認
                 │                      │
                 │              ┌───────┴───────┐
                 │              │               │
                 │         [ヒット]        [ミス]
                 │              │               │
                 │              │          importPlugin
                 │              │               │
                 ▼              ▼               ▼
              そのまま     キャッシュ      モジュール正規化
              返却         から返却        & キャッシュ保存
                 │              │               │
                 └──────────────┴───────────────┘
                                │
                                ▼
                         プラグイン配列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/main/plugins/index.js` | ソース | プラグインシステムのエクスポート |
| load-plugins.js | `src/main/plugins/load-plugins.js` | ソース | 複数プラグインの並列読み込み |
| load-plugin.js | `src/main/plugins/load-plugin.js` | ソース | 単一プラグインの読み込みとキャッシュ管理 |
| load-builtin-plugins.js | `src/main/plugins/load-builtin-plugins.js` | ソース | ビルトインプラグインの遅延読み込み |
| utilities.js | `src/main/plugins/builtin-plugins/utilities.js` | ソース | プラグイン型定義とユーティリティ |
| import-from-directory.js | `src/utilities/import-from-directory.js` | ソース | ディレクトリからのモジュールインポート |
