# バッチ設計書 14-babel-plugin-jest-native-globals

## 概要

本ドキュメントは、Jestリポジトリのビルド時に使用されるBabelプラグイン `babel-plugin-jest-native-globals.js` の設計仕様を記載する。このプラグインは、特定パッケージ向けにネイティブグローバル変数をガードする変換を行う。

### 本バッチの処理概要

このプラグインは、Jestのサンドボックス環境で注入されるモジュール向けに、ユーザーコードによって改変されていないネイティブのグローバル変数（Promise、Symbol、Date.now、fs操作）を使用するためのコード変換を実行する。

**業務上の目的・背景**：Jestはテスト実行時にサンドボックス環境を構築し、モジュールを隔離して実行する。このとき、ユーザーのテストコードがPromiseやSymbolなどのグローバルオブジェクトをモック・改変している可能性がある。Jest内部のコード（特にスナップショット機能やマッチャー）は、改変されていないネイティブのグローバル変数に依存する必要があるため、このプラグインを使用してビルド時に安全な参照に書き換える。これにより、ユーザーがグローバルをどのように変更しても、Jest内部の動作が影響を受けないことを保証する。

**バッチの実行タイミング**：build.mjsによるWebpackビルド時に、babel-loaderのプラグインとして実行される。INLINE_REQUIRE_EXCLUDE_LISTにマッチするパッケージのビルド時にのみ適用される。

**主要な処理内容**：
1. Promise参照をjest-native-promise Symbolから取得したPromiseに置換
2. Symbol参照をjest-symbol-do-not-touchから取得したSymbolに置換
3. Date.now呼び出しをjest-native-now Symbolから取得した関数に置換
4. fs.readFileSync/writeFileSync/existsSync呼び出しを対応するネイティブ関数に置換

**前後の処理との関連**：buildUtils.mjsのcreateBuildConfigs関数から、INLINE_REQUIRE_EXCLUDE_LISTにマッチするパッケージに対してこのプラグインが設定される。ビルド後のコードはJestランタイムで実行され、jest-runtimeがこれらのSymbolをglobalThisに設定する。

**影響範囲**：expect、jest-circus、jest-diff、jest-get-type、jest-jasmine2、jest-matcher-utils、jest-message-util、jest-regex-util、jest-snapshot、pretty-formatパッケージのビルド成果物に影響する。

## バッチ種別

ユーティリティ / Babelプラグイン

## 実行スケジュール

| 項目 | 内容 |
|-----|------|
| 実行頻度 | ビルド時（babel-loaderのプラグインとして） |
| 実行時刻 | 指定なし |
| 実行曜日 | 指定なし |
| 実行日 | 指定なし |
| トリガー | Webpackビルド（yarn build:js） |

## 実行条件

### 前提条件

| 条件 | 説明 |
|-----|------|
| Babel環境 | Babelがインストールされ、babel-loaderが設定されていること |
| ビルドコンテキスト | buildUtils.mjsのcreateBuildConfigs経由で呼び出されること |
| 対象パッケージ | INLINE_REQUIRE_EXCLUDE_LISTにマッチするパッケージであること |

### 実行可否判定

buildUtils.mjsのcreateBuildConfigs関数内で、パッケージパスがINLINE_REQUIRE_EXCLUDE_LISTの正規表現にマッチする場合にのみプラグインが適用される。

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | デフォルト値 | 説明 |
|-------------|-----|-----|-------------|------|
| template | Function | Yes | - | Babelから渡されるテンプレートヘルパー関数 |

### 入力データソース

| データソース | 形式 | 説明 |
|-------------|------|------|
| ソースコードAST | Babel AST | 変換対象のJavaScript/TypeScriptコードのAST |

## 出力仕様

### 出力データ

| 出力先 | 形式 | 説明 |
|-------|------|------|
| 変換後AST | Babel AST | グローバル変数参照が置換されたAST |

### 出力ファイル仕様

ファイル出力は行わない。Babelパイプラインの一部として、変換後のASTを次の処理に渡す。

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   └─ template関数を使用して各宣言のテンプレートを定義
2. Promise宣言テンプレート作成
   └─ globalThis[Symbol.for('jest-native-promise')] || globalThis.Promise
3. Symbol宣言テンプレート作成
   └─ globalThis['jest-symbol-do-not-touch'] || globalThis.Symbol
4. Date.now宣言テンプレート作成
   └─ globalThis[Symbol.for('jest-native-now')] || globalThis.Date.now
5. fs操作宣言テンプレート作成
   └─ readFileSync、writeFileSync、existsSyncの各テンプレート
6. visitorオブジェクト返却
   └─ ReferencedIdentifierハンドラを定義
7. AST走査時の処理
   └─ 7.1. Promise参照を検出し、宣言を挿入・フラグ設定
   └─ 7.2. Symbol参照を検出し、宣言を挿入・フラグ設定
   └─ 7.3. Date.now参照を検出し、jestNowに置換・宣言挿入
   └─ 7.4. fs.readFileSync等を検出し、対応関数に置換・宣言挿入
```

### フローチャート

```mermaid
flowchart TD
    A[Babelプラグイン開始] --> B[テンプレート定義]
    B --> C[AST走査開始]
    C --> D{識別子タイプ?}
    D -->|Promise| E{既に注入済み?}
    E -->|No| F[Promise宣言をファイル先頭に挿入]
    E -->|Yes| G[スキップ]
    D -->|Symbol| H{既に注入済み?}
    H -->|No| I[Symbol宣言をファイル先頭に挿入]
    H -->|Yes| G
    D -->|Date.now| J{既に注入済み?}
    J -->|No| K[jestNow宣言挿入 + 参照置換]
    J -->|Yes| L[参照置換のみ]
    D -->|fs.*Sync| M{該当メソッド?}
    M -->|Yes| N[対応するjest*関数に置換]
    M -->|No| G
    F --> O[次の識別子へ]
    I --> O
    K --> O
    L --> O
    N --> O
    G --> O
    O --> P{AST走査完了?}
    P -->|No| D
    P -->|Yes| Q[変換後AST返却]
```

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

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

| 処理 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| なし | - | - | データベース操作は行わない |

### テーブル別操作詳細

データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| BabelError | 構文エラー | 入力コードが不正なAST構造 | ソースコードの構文を確認 |
| TypeError | 型エラー | templateが未定義 | Babelバージョンの互換性を確認 |

### リトライ仕様

| 項目 | 内容 |
|-----|------|
| リトライ回数 | なし |
| リトライ間隔 | なし |
| リトライ対象エラー | なし |

### 障害時対応

このプラグインでエラーが発生した場合：
1. Babelのエラーメッセージを確認
2. 対象ファイルの構文を確認
3. Babelおよび関連パッケージのバージョン互換性を確認
4. ビルドを再実行

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

| 項目 | 内容 |
|-----|------|
| トランザクション範囲 | なし（AST変換） |
| コミットタイミング | なし |
| ロールバック条件 | なし |

## パフォーマンス要件

| 項目 | 内容 |
|-----|------|
| 想定処理件数 | 対象パッケージのすべてのソースファイル |
| 目標処理時間 | ファイルあたりミリ秒単位 |
| メモリ使用量上限 | Babelの標準的な使用量 |

## 排他制御

Babelプラグインとして同期的に実行されるため、排他制御は不要。

## ログ出力

| ログ種別 | 出力タイミング | 出力内容 |
|---------|--------------|---------|
| なし | - | ログ出力機能なし |

## 監視・アラート

| 監視項目 | 閾値 | アラート先 |
|---------|-----|----------|
| なし | - | 監視機能なし |

## 備考

### 変換対象グローバル変数

| 元の参照 | 変換後の参照 | ネイティブ取得元 |
|---------|------------|----------------|
| Promise | Promise（宣言追加） | globalThis[Symbol.for('jest-native-promise')] |
| Symbol | Symbol（宣言追加） | globalThis['jest-symbol-do-not-touch'] |
| Date.now | jestNow | globalThis[Symbol.for('jest-native-now')] |
| fs.readFileSync | jestReadFile | globalThis[Symbol.for('jest-native-read-file')] |
| fs.writeFileSync | jestWriteFile | globalThis[Symbol.for('jest-native-write-file')] |
| fs.existsSync | jestExistsFile | globalThis[Symbol.for('jest-native-exists-file')] |

### 適用対象パッケージ

INLINE_REQUIRE_EXCLUDE_LISTの正規表現にマッチするパッケージ：
```
/packages\/expect|(jest-(circus|diff|get-type|jasmine2|matcher-utils|message-util|regex-util|snapshot))|pretty-format\//
```

### ランタイム側の対応

jest-runtimeがテスト実行前にこれらのSymbolをglobalThisに設定し、ネイティブの関数を保存する。これにより、ビルド時に変換されたコードが実行時に正しいネイティブ関数を参照できる。

### state管理

各ファイルの変換時に、stateオブジェクトを使用して既に宣言を挿入したかどうかを追跡：
- state.jestInjectedPromise
- state.jestInjectedSymbol
- state.jestInjectedNow
- state.jestInjectedRead
- state.jestInjectedWrite
- state.jestInjectedExists
