# 機能設計書 33-@babel/plugin-transform-private-property-in-object

## 概要

本ドキュメントは、Babelの変換プラグイン「@babel/plugin-transform-private-property-in-object」の機能設計を記述する。本プラグインはES2022のin演算子によるプライベートプロパティチェック構文（`#prop in obj`）を、古いJavaScript環境でも動作する形式に変換する。

### 本機能の処理概要

本プラグインは、in演算子の左辺にプライベート名（#接頭辞付き識別子）を指定した式を、WeakSetを用いたブランドチェック実装に変換する機能を提供する。これにより、あるオブジェクトが特定のプライベートプロパティを持つかどうかを安全に判定できる。

**業務上の目的・背景**：ES2022で導入されたこの機能は、オブジェクトが特定のクラスのインスタンスであるかを安全に判定するために使用される。従来のinstanceof演算子とは異なり、プライベートフィールドの存在を直接チェックするため、より正確な型判定が可能となる。古いJavaScript環境ではこの構文をサポートしていないため、トランスパイルが必要となる。

**機能の利用シーン**：
- オブジェクトの型を安全に判定する必要があるライブラリ開発
- プライベートフィールドの存在に基づく条件分岐
- `@babel/preset-env`の一部として自動的に適用される場合

**主要な処理内容**：
1. BinaryExpressionノードでin演算子かつ左辺がPrivateNameの式を検出
2. 対象のプライベートプロパティが属するクラスを特定
3. 静的プライベートメソッドの場合はクラス参照との等価性チェックに変換
4. インスタンスプライベートプロパティの場合はWeakSetを用いたhas()チェックに変換
5. プライベートフィールドの場合は専用のWeakSetを生成しhas()チェックに変換

**関連システム・外部連携**：
- `@babel/helper-create-class-features-plugin`: privateIn機能フラグの有効化
- `@babel/helper-annotate-as-pure`: WeakSet生成をpureとしてマーク
- `@babel/helper-plugin-utils`: プラグインユーティリティ
- `@babel/core`: Babelコアとの統合

**権限による制御**：特になし。変換はビルド時に実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIまたはビルドツール経由で使用されるため、画面との関連なし |

## 機能種別

コード変換処理 / AST操作

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| loose | boolean | No | trueの場合、仕様準拠よりもパフォーマンスを優先した簡易な変換を行う | boolean型であること |

### 入力データソース

- Babelによってパースされたソースコード（AST形式）
- 特にBinaryExpression（operator: "in"、left: PrivateName）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| transformedAST | AST | 変換後のAST |

### 出力先

- 変換されたASTは`@babel/generator`によってJavaScriptコードとして出力

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化（pre関数）
   └─ enableFeature関数でFEATURES.privateInを有効化

2. BinaryExpressionノードの訪問
   └─ operator === "in" かつ left がPrivateNameかをチェック

3. プライベートプロパティの検索
   └─ 親クラスを走査し、対象のプライベートプロパティを特定

4. プロパティの種類に応じた変換
   ├─ ClassPrivateMethod（静的）: クラス参照との等価性チェック
   ├─ ClassPrivateMethod（インスタンス）: クラスのWeakSetでhas()チェック
   └─ ClassPrivateProperty: フィールド専用WeakSetでhas()チェック

5. WeakSetの生成と初期化コード挿入
   └─ クラス定義前にWeakSet変数を宣言、コンストラクタでadd()
```

### フローチャート

```mermaid
flowchart TD
    A[BinaryExpressionの訪問] --> B{in演算子 かつ 左辺がPrivateName?}
    B -->|No| Z[変換なし]
    B -->|Yes| C[親クラスでプライベートプロパティを検索]
    C --> D{プロパティの種類}
    D -->|静的メソッド| E[クラス === RHS に変換]
    D -->|インスタンスメソッド| F[classWeakSet.has RHS に変換]
    D -->|プライベートフィールド| G[fieldWeakSet.has RHS に変換]
    E --> H[変換完了]
    F --> H
    G --> I[WeakSet生成と初期化コード挿入]
    I --> H
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-33-01 | 静的メソッドのチェック | 静的プライベートメソッドはクラス自体との等価性でチェック | 静的メソッド使用時 |
| BR-33-02 | インスタンスメソッドのチェック | インスタンスプライベートメソッドはクラス全体のWeakSetでチェック | インスタンスメソッド使用時 |
| BR-33-03 | フィールドのチェック | プライベートフィールドは各フィールド専用のWeakSetでチェック | フィールド使用時 |
| BR-33-04 | RHSの検証 | 右辺がオブジェクトでない場合はエラー | buildCheckInRHS使用時 |

### 計算ロジック

特になし（構文変換のため）

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

該当なし（コンパイル時変換のため）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | SyntaxError | 不正なin演算子構文 | パーサーレベルでエラー |
| - | TypeError | 右辺がオブジェクトでない | 実行時エラー |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

- 変換処理は同期的に実行される
- WeakSetを使用することで、オブジェクトのガベージコレクションを阻害しない

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

- プライベートプロパティの存在チェックは、外部からプロパティ値にアクセスすることなく実行可能

## 備考

- 本プラグインは`@babel/preset-env`に含まれており、ターゲット環境に応じて自動的に適用される
- クラスフィールドやプライベートメソッドのプラグインと併用される場合、それらのプラグインが変換処理を担当することもある

---

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

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

### 推奨読解順序

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

本プラグインはBinaryExpression（in演算子）とPrivateNameを変換対象とする。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-private-property-in-object/src/index.ts` | Optionsインターフェース、classWeakSetsとfieldsWeakSetsのWeakMap定義 |

**読解のコツ**: このプラグインは独自のビジター実装を持ち、`helper-create-class-features-plugin`との連携方法を理解することが重要。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/babel-plugin-transform-private-property-in-object/src/index.ts` | pre関数でFEATURES.privateInを有効化、BinaryExpressionビジターの実装 |

**主要処理フロー**:
1. **1-8行目**: 必要なモジュールのインポート（enableFeature, FEATURES, buildCheckInRHS等）
2. **14-18行目**: プラグインの宣言とAPIバージョン検証
3. **25-29行目**: classWeakSetsとfieldsWeakSetsのWeakMap定義
4. **31-36行目**: unshadow関数 - スコープ内の変数名衝突を解決
5. **38-53行目**: injectToFieldInit関数 - フィールド初期化子に式を挿入
6. **55-82行目**: injectInitialization関数 - クラスの初期化処理を挿入
7. **84-110行目**: getWeakSetId関数 - WeakSetの生成と管理
8. **115-118行目**: pre関数でFEATURES.privateInを有効化
9. **121-201行目**: BinaryExpressionビジター - 変換処理のメインロジック

#### Step 3: ビジターのロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts (121-201行目) | `packages/babel-plugin-transform-private-property-in-object/src/index.ts` | BinaryExpressionビジターの条件分岐と変換処理 |

**主要処理フロー**:
- **122-125行目**: in演算子かつ左辺がPrivateNameかをチェック
- **127-142行目**: 親クラスを走査してプライベートプロパティを検索
- **144-150行目**: パターン内のクラスをIIFEでラップ
- **152-182行目**: ClassPrivateMethodの変換（静的/インスタンス）
- **183-200行目**: ClassPrivatePropertyの変換

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

```
@babel/plugin-transform-private-property-in-object/src/index.ts
    │
    ├─ pre()
    │      └─ enableFeature(FEATURES.privateIn)
    │
    └─ visitor.BinaryExpression()
           │
           ├─ findParent() で親クラスを検索
           │
           ├─ ClassPrivateMethod の場合
           │      ├─ static: クラス === RHS
           │      └─ instance: getWeakSetId() → has(RHS)
           │
           └─ ClassPrivateProperty の場合
                  └─ getWeakSetId() → has(RHS)
                         │
                         ├─ WeakSet生成（annotateAsPure）
                         └─ injectToFieldInit() または injectInitialization()
```

### データフロー図

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

#prop in obj 式  ─▶  BinaryExpression visitor      ─▶  weakSet.has(obj) 式
(AST)                         │                         (AST)
                              │
                              ├─ プロパティ種別判定
                              ├─ WeakSet生成
                              └─ 初期化コード挿入
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-private-property-in-object/src/index.ts` | ソース | プラグインエントリーポイント、変換ロジック |
| package.json | `packages/babel-plugin-transform-private-property-in-object/package.json` | 設定 | パッケージ依存関係定義 |
| test/index.js | `packages/babel-plugin-transform-private-property-in-object/test/index.js` | テスト | テストランナー設定 |
| fixtures/private/ | `packages/babel-plugin-transform-private-property-in-object/test/fixtures/private/` | テスト | 標準モードのテストケース |
| fixtures/to-native-fields/ | `packages/babel-plugin-transform-private-property-in-object/test/fixtures/to-native-fields/` | テスト | ネイティブフィールド対応テスト |
