# 機能設計書 52-TypeScript Plugin

## 概要

本ドキュメントは、Payload CMS用のTypeScript Language Service Pluginの機能設計を定義する。このプラグインは、PayloadComponentのインポートパス検証と自動補完をIDEに提供する開発支援ツールである。

### 本機能の処理概要

TypeScript Pluginは、VS CodeやWebStorm等のIDEにおいて、PayloadComponentの文字列パス指定に対するリアルタイム検証、自動補完、定義ジャンプ機能を提供する。

**業務上の目的・背景**：Payload CMSでは、カスタムコンポーネント（フィールドコンポーネント、ビューコンポーネント等）を文字列パスで指定する。例えば`'@/components/MyField#MyField'`のような形式でパスとエクスポート名を指定する。この文字列ベースの指定は実行時エラーの原因となりやすく、開発時に検証できないという課題があった。TypeScript Pluginはこの課題を解決し、開発体験を大幅に向上させる。

**機能の利用シーン**：
- Payload設定ファイル（payload.config.ts）でカスタムコンポーネントを指定する際
- フィールド定義でカスタムフィールドコンポーネントを設定する際
- 管理画面のカスタムビューを定義する際
- 既存コンポーネントの定義元へジャンプする際

**主要な処理内容**：
1. 診断（Diagnostics）: PayloadComponent文字列のモジュールパスとエクスポート名の検証
2. 自動補完（Completions）: パスの補完候補とモジュールエクスポートの候補を提示
3. 定義ジャンプ（Go-to-Definition）: PayloadComponent文字列からソースファイルへのナビゲーション
4. baseDir検出: payload.config.tsからプロジェクトのベースディレクトリを自動検出
5. モジュール解決: TypeScriptのモジュール解決を活用したパス解決

**関連システム・外部連携**：
- TypeScript Language Service: プラグインのホスト環境
- VS Code / WebStorm等のIDE: プラグインの利用環境
- Payload CMS設定システム: PayloadComponent型の定義元

**権限による制御**：開発ツールのため、権限制御は存在しない。

## 関連画面

本機能は開発支援ツールであり、Payload CMSの管理画面とは直接関連しない。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 管理画面との直接の関連なし |

## 機能種別

開発支援ツール / IDE統合 / 静的解析

## 入力仕様

### 入力パラメータ

#### プラグイン設定（tsconfig.json）

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | プラグイン名（@payloadcms/typescript-plugin） | 固定値 |
| baseDir | string | No | ベースディレクトリパス（省略時は自動検出） | 相対パス |

#### PayloadComponent文字列形式

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| path | string | Yes | モジュールパス | '/'または'./'で始まる、または@エイリアス |
| exportName | string | No | エクスポート名（#以降、デフォルトは'default'） | 有効な識別子 |

### 入力データソース

- TypeScript設定ファイル: tsconfig.json内のplugins配列
- ソースコード: PayloadComponent型の文字列リテラル
- ファイルシステム: モジュール解決時のファイル検索

## 出力仕様

### 出力データ

#### 診断結果（Diagnostics）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| code | number | エラーコード（71001: モジュール未発見、71002: エクスポート未発見） |
| category | DiagnosticCategory | Error |
| messageText | string | エラーメッセージ |
| file | SourceFile | 対象ファイル |
| start | number | エラー開始位置 |
| length | number | エラー範囲長 |

#### 補完候補（CompletionInfo）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| entries | CompletionEntry[] | 補完候補リスト |
| isGlobalCompletion | boolean | グローバル補完フラグ |
| isMemberCompletion | boolean | メンバー補完フラグ |
| isNewIdentifierLocation | boolean | 新規識別子位置フラグ |

#### 定義情報（DefinitionInfoAndBoundSpan）

| 項目名 | 型 | 説明 |
|--------|-----|------|
| definitions | DefinitionInfo[] | 定義情報リスト |
| textSpan | TextSpan | ソーステキスト範囲 |

### 出力先

- IDE: 診断結果、補完候補、定義ジャンプ先として表示

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化（init/create）
   └─ LanguageServiceのプロキシ作成
2. getSemanticDiagnostics
   └─ PayloadComponent文字列の検証
       ├─ モジュールパス解決
       └─ エクスポート存在確認
3. getCompletionsAtPosition
   └─ カーソル位置の判定
       ├─ パス補完（#前）
       └─ エクスポート補完（#後）
4. getDefinitionAndBoundSpan
   └─ PayloadComponent文字列からの定義ジャンプ
       ├─ モジュール解決
       └─ エクスポートシンボル検索
```

### フローチャート

```mermaid
flowchart TD
    A[文字列リテラルを検出] --> B{PayloadComponent コンテキストか}
    B -->|No| C[標準処理に委譲]
    B -->|Yes| D[コンテキストタイプを判定]
    D --> E{タイプ}
    E -->|string| F[path#exportName形式を解析]
    E -->|path| G[pathプロパティとして処理]
    E -->|exportName| H[exportNameプロパティとして処理]
    F --> I[モジュールパスを解決]
    G --> I
    H --> I
    I --> J{モジュールが存在するか}
    J -->|No| K[エラー71001: モジュール未発見]
    J -->|Yes| L[エクスポートを取得]
    L --> M{エクスポートが存在するか}
    M -->|No| N[エラー71002: エクスポート未発見]
    M -->|Yes| O[検証成功]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-52-01 | パス形式 | '/'または'./'で始まるパスはbaseDirからの相対パス | パスが/または./で始まる場合 |
| BR-52-02 | デフォルトエクスポート | #以降が省略された場合は'default'エクスポートを参照 | exportName未指定時 |
| BR-52-03 | 拡張子省略 | .tsx/.ts/.jsx/.jsは省略可能 | モジュール解決時 |
| BR-52-04 | baseDir自動検出 | payload.config.tsを上方向に検索してbaseDirを決定 | baseDir設定が未指定時 |
| BR-52-05 | スペル提案 | エクスポート名が存在しない場合、類似名を提案 | エクスポート未発見エラー時 |

### 計算ロジック

**PayloadComponentパース処理**:
```typescript
// '#'でパスとエクスポート名を分割
if (pathAndMaybeExport.includes('#')) {
  [path, exportName] = pathAndMaybeExport.split('#', 2)
  exportName = exportName || 'default'
} else {
  path = pathAndMaybeExport
  exportName = 'default'
}
```

**baseDir検出ロジック**:
```
1. 現在のファイルの親ディレクトリから開始
2. payload.config.ts, payload.config.js, config.tsを検索
3. 見つかったディレクトリをbaseDirとして返却
4. ルートまで到達した場合はundefined
```

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

TypeScript Pluginはデータベースを操作しない。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| 71001 | モジュール未発見 | 指定されたパスのモジュールが存在しない | パスの確認、ファイルの存在確認 |
| 71002 | エクスポート未発見 | モジュールに指定されたエクスポートが存在しない | エクスポート名の確認、提案された名前の使用 |

### リトライ仕様

リトライは行わない。エラーは即時にIDEに表示される。

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

トランザクション管理は不要。

## パフォーマンス要件

- baseDirの検出結果はファイル単位でキャッシュ
- TypeScriptの標準モジュール解決を使用することで高速な解決を実現
- 補完候補はプレフィックスでフィルタリングして結果を絞り込み

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

- 開発ツールのため、本番環境では使用されない
- ファイルシステムへのアクセスはTypeScript Language Service経由で行われる
- 外部ネットワークへのアクセスは行わない

## 備考

- TypeScript 5.7.3以上が必要
- VS Code、WebStorm、その他TypeScript Language Serviceをサポートするエディタで使用可能
- プラグインの有効化にはtsconfig.jsonのpluginsへの追加が必要

---

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

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

### 推奨読解順序

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

まず、PayloadComponentコンテキストの型定義を理解することが重要。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | helpers.ts | `packages/typescript-plugin/src/helpers.ts` | PayloadComponentContext型と判定ロジック |

**読解のコツ**:
- **3-6行目**: `PayloadComponentContext`型は3種類（string/path/exportName）のユニオン
- **15-46行目**: `getPayloadComponentContext`関数でコンテキスト判定
- **69-97行目**: `isPayloadComponentType`で型の判定（エイリアス名または構造的チェック）

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

プラグインの初期化とLanguageServiceプロキシの作成を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/typescript-plugin/src/index.ts` | プラグイン初期化、プロキシ作成 |

**主要処理フロー**:
1. **7-8行目**: `init`関数がTypeScriptモジュールを受け取る
2. **10-12行目**: `create`関数でPluginCreateInfoからLanguageServiceを作成
3. **20-26行目**: LanguageServiceの全メソッドをプロキシとしてラップ
4. **28-47行目**: `getBaseDir`でbaseDir設定または自動検出

#### Step 3: 診断機能を理解する

PayloadComponent文字列の検証処理を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/typescript-plugin/src/index.ts` | getPayloadDiagnostics関数 |

**主要処理フロー**:
- **49-67行目**: `getSemanticDiagnostics`のプロキシ実装
- **219-293行目**: `getPayloadDiagnostics`でAST走査と検証
- **228-234行目**: 文字列リテラルを検出しコンテキスト判定
- **244-254行目**: モジュール解決失敗時のエラー生成（71001）
- **256-284行目**: エクスポート未発見時のエラー生成（71002）、スペル提案付き

#### Step 4: 補完機能を理解する

パスとエクスポートの自動補完処理を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | index.ts | `packages/typescript-plugin/src/index.ts` | getPayloadCompletions、buildExportCompletions、getPathCompletions |

**主要処理フロー**:
- **69-93行目**: `getCompletionsAtPosition`のプロキシ実装
- **299-340行目**: `getPayloadCompletions`でコンテキスト別の補完処理
- **313-318行目**: exportNameコンテキストの場合はエクスポート補完
- **321-337行目**: #の位置でパス補完かエクスポート補完かを判定
- **382-493行目**: `getPathCompletions`でディレクトリ・ファイルの補完

#### Step 5: 定義ジャンプ機能を理解する

Go-to-Definition処理を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | index.ts | `packages/typescript-plugin/src/index.ts` | getPayloadDefinition関数 |

**主要処理フロー**:
- **95-114行目**: `getDefinitionAndBoundSpan`のプロキシ実装
- **499-581行目**: `getPayloadDefinition`で定義情報を構築
- **518-527行目**: モジュール解決
- **539-566行目**: エクスポートシンボルを検索し宣言位置を取得

#### Step 6: モジュール解決を理解する

TypeScriptのモジュール解決を活用したパス解決を把握。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 6-1 | index.ts | `packages/typescript-plugin/src/index.ts` | resolveModulePath、resolveToDir |

**主要処理フロー**:
- **167-195行目**: `resolveModulePath`でPayload規約に従うパス解決
- **179-189行目**: '/'や'./'パスをbaseDirからの相対パスとして処理
- **193行目**: TypeScriptの標準`resolveModuleName`を使用
- **588-610行目**: `resolveToDir`でディレクトリパスを解決

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

```
init (index.ts)
    │
    └─ create
           │
           ├─ getSemanticDiagnostics (プロキシ)
           │      └─ getPayloadDiagnostics
           │             ├─ getPayloadComponentContext (helpers.ts)
           │             ├─ parsePayloadComponent
           │             ├─ resolveModulePath
           │             └─ getModuleExports
           │
           ├─ getCompletionsAtPosition (プロキシ)
           │      └─ getPayloadCompletions
           │             ├─ getPayloadComponentContext (helpers.ts)
           │             ├─ buildExportCompletions
           │             │      └─ getModuleExports
           │             └─ getPathCompletions
           │                    └─ resolveToDir
           │
           └─ getDefinitionAndBoundSpan (プロキシ)
                  └─ getPayloadDefinition
                         ├─ getPayloadComponentContext (helpers.ts)
                         ├─ parsePayloadComponent
                         └─ resolveModulePath
```

### データフロー図

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

ソースファイル ──────┐
                     │
カーソル位置 ───────┼──▶ LanguageService ──▶ 診断結果
                     │       プロキシ        ─▶ 補完候補
tsconfig設定 ───────┘                        ─▶ 定義情報

                            │
                            ▼
                  PayloadComponentContext判定
                            │
              ┌─────────────┼─────────────┐
              ▼             ▼             ▼
           string形式    path形式   exportName形式
              │             │             │
              └─────────────┼─────────────┘
                            ▼
                    モジュール解決
                            │
                            ▼
                    エクスポート取得
                            │
                            ▼
                      結果生成
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/typescript-plugin/src/index.ts` | ソース | プラグインメイン実装 |
| helpers.ts | `packages/typescript-plugin/src/helpers.ts` | ソース | コンテキスト判定ヘルパー |
| package.json | `packages/typescript-plugin/package.json` | 設定 | パッケージ定義 |
| plugin.spec.ts | `packages/typescript-plugin/src/__tests__/plugin.spec.ts` | テスト | プラグインテスト |
| tsconfig.json | `packages/typescript-plugin/tsconfig.json` | 設定 | TypeScript設定 |
