# 機能設計書 30-jest-util

## 概要

本ドキュメントは、Jestの汎用ユーティリティパッケージ（jest-util）の機能設計を記述する。このパッケージは、Jest内部で使用される様々な汎用ユーティリティ関数を提供する。

### 本機能の処理概要

jest-utilは、Jestフレームワーク全体で使用される共通ユーティリティ関数を集約したパッケージである。グローバル設定、オブジェクトのディープコピー、Globマッチング、モジュールの動的インポート、ガベージコレクション管理など、多岐にわたる機能を提供する。

**業務上の目的・背景**：Jestの各パッケージで共通して使用される処理をユーティリティとして集約することで、コードの重複を排除し、一貫性のある動作を保証する。また、テスト環境の分離やメモリ管理などの複雑な処理を抽象化する。

**機能の利用シーン**：
- テスト環境の初期化
- グローバル変数の設定
- 設定ファイルの読み込み
- テストファイルパスのマッチング
- メモリリーク防止のためのガベージコレクション

**主要な処理内容**：
1. installCommonGlobals: グローバルオブジェクトの設定
2. deepCyclicCopy: 循環参照対応のディープコピー
3. globsToMatcher: Globパターンからマッチャー関数を生成
4. requireOrImportModule: CJS/ESMモジュールの動的読み込み
5. createProcessObject: 隔離されたprocessオブジェクトの作成
6. ガベージコレクションユーティリティ（deleteProperties, protectProperties）

**関連システム・外部連携**：
- @jest/types: 設定型定義
- picomatch: Globマッチング
- graceful-fs: ファイルシステム操作
- chalk: カラー出力

**権限による制御**：この機能に権限による制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本パッケージは内部ユーティリティを提供 |

## 機能種別

内部ユーティリティ / 共通関数ライブラリ

## 入力仕様

### 主要関数の入力パラメータ

#### installCommonGlobals

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| globalObject | typeof globalThis | Yes | 設定対象のグローバルオブジェクト | - |
| globals | Config.ConfigGlobals | Yes | 設定するグローバル変数 | - |
| garbageCollectionDeletionMode | DeletionMode | No | ガベージコレクションモード | 'soft'\|'off'\|'on' |

#### deepCyclicCopy

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| value | T | Yes | コピー対象の値 | - |
| options | DeepCyclicCopyOptions | No | コピーオプション | - |

#### globsToMatcher

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| globs | Array<string> | Yes | Globパターン配列 | - |
| picomatchOptions | PicomatchOptions | No | picomatchオプション | - |

#### requireOrImportModule

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| filePath | string | Yes | モジュールパス | 絶対パス必須 |
| applyInteropRequireDefault | boolean | No | デフォルトエクスポートを適用 | デフォルト: true |

### 入力データソース

- Jest設定ファイル
- テストファイルパス
- グローバル設定オブジェクト

## 出力仕様

### 主要関数の出力データ

| 関数名 | 戻り値型 | 説明 |
|--------|---------|------|
| installCommonGlobals | typeof globalThis & Config.ConfigGlobals | 設定済みグローバルオブジェクト |
| deepCyclicCopy | T | コピーされたオブジェクト |
| globsToMatcher | (str: string) => boolean | マッチャー関数 |
| requireOrImportModule | Promise<T> | 読み込んだモジュール |
| createProcessObject | typeof Process | 新しいprocessオブジェクト |
| formatTime | string | フォーマット済み時間文字列 |

### 出力先

- Jest内部の各パッケージ

## 処理フロー

### installCommonGlobals処理シーケンス

```
1. createProcessObject()でprocessを作成
   └─ deepCyclicCopyでprocessをコピー
   └─ createProcessEnv()でプロキシ化されたenv作成

2. グローバルシンボルの設定
   └─ jest-native-promise: Promise参照
   └─ jest-native-now: Date.now参照
   └─ jest-native-read-file: fs.readFileSync参照
   └─ jest-native-write-file: fs.writeFileSync参照
   └─ jest-native-exists-file: fs.existsSync参照
   └─ jest-symbol-do-not-touch: Symbol参照

3. DTRACEの転送設定

4. ガベージコレクション初期化（オプション）
   └─ initializeGarbageCollectionUtils()

5. グローバル変数のマージ
   └─ deepCyclicCopy(globals)をglobalObjectに割り当て
```

### フローチャート

```mermaid
flowchart TD
    A[installCommonGlobals] --> B[createProcessObject]
    B --> C[deepCyclicCopy process]
    C --> D[createProcessEnv]
    D --> E[グローバルシンボル設定]
    E --> F{GC mode?}
    F -->|あり| G[initializeGarbageCollectionUtils]
    F -->|なし| H[globalsをマージ]
    G --> H
    H --> I[設定済みglobalObject返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-30-01 | パス絶対パス必須 | requireOrImportModuleは絶対パス必須 | 常時 |
| BR-30-02 | ESM自動検出 | .mjsまたはERR_REQUIRE_ESMでESMインポート | モジュール読み込み時 |
| BR-30-03 | Glob空配列 | globs配列が空の場合は常にfalseを返す | globsToMatcher |
| BR-30-04 | 削除モード | soft/off/onの3モードでガベージコレクション制御 | GC初期化時 |
| BR-30-05 | Win32大文字小文字 | Windowsではprocess.envが大文字小文字無視 | createProcessEnv |
| BR-30-06 | 循環参照対応 | WeakMapで循環参照を追跡しコピー | deepCyclicCopy |

### 計算ロジック

#### formatTime

```typescript
// 時間を適切な単位でフォーマット
// prefixPower: -3 = ms, -6 = μs, -9 = ns
const prefixes = ['n', 'μ', 'm', ''];  // ns, μs, ms, s
const prefixIndex = Math.max(0, Math.min(
  Math.trunc(prefixPower / 3) + prefixes.length - 1,
  prefixes.length - 1
));
return `${String(time).padStart(padLeftLength)} ${prefixes[prefixIndex]}s`;
```

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

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

データベース操作は存在しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | requireOrImportModuleで相対パス指定 | 絶対パスを使用 |
| - | Error | ESMモジュールにdefault exportがない | default exportを追加 |
| - | Error | dynamic importがサポートされていない | .cjs拡張子を使用 |
| JEST-01 | DeprecationWarning | soft削除されたプロパティへのアクセス | globalsCleanup設定を確認 |

### リトライ仕様

リトライ処理は存在しない。

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

トランザクション処理は存在しない。

## パフォーマンス要件

- globsToMatcherはマッチャーをキャッシュして再利用
- deepCyclicCopyはWeakMapで循環参照を追跡し無限ループを防止

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

- requireOrImportModuleは任意のコードを実行可能なため、信頼できるパスのみを使用すること

## 備考

- jest-utilはJest内部で広く使用される基盤パッケージ
- ガベージコレクションユーティリティはテスト間のメモリリークを防止

---

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

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

### 推奨読解順序

#### Step 1: エクスポート一覧を把握する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/jest-util/src/index.ts` | エクスポート一覧 |

**読解のコツ**:
- 全エクスポートを把握して全体像を理解する
- specialCharsとpreRunMessageはnamespaceとしてエクスポート

#### Step 2: 主要ユーティリティを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | installCommonGlobals.ts | `packages/jest-util/src/installCommonGlobals.ts` | グローバル設定 |
| 2-2 | createProcessObject.ts | `packages/jest-util/src/createProcessObject.ts` | process作成 |
| 2-3 | deepCyclicCopy.ts | `packages/jest-util/src/deepCyclicCopy.ts` | ディープコピー |

**主要処理フロー (installCommonGlobals.ts)**:
- **19-23行目**: 関数定義と引数
- **24行目**: createProcessObject()でprocess作成
- **28-59行目**: グローバルシンボルの設定
  - **29-33行目**: jest-native-promise
  - **34-38行目**: jest-native-now
  - **39-43行目**: jest-native-read-file
  - **44-48行目**: jest-native-write-file
  - **49-53行目**: jest-native-exists-file
  - **54-58行目**: jest-symbol-do-not-touch
- **62-68行目**: DTRACE転送
- **70-75行目**: ガベージコレクション初期化
- **77行目**: globalsのマージ

**主要処理フロー (createProcessObject.ts)**:
- **11行目**: BLACKLIST定義（env, mainModule, _events）
- **20-81行目**: createProcessEnv()でプロキシ化されたenv作成
- **83-148行目**: createProcessObject()
  - **85-88行目**: deepCyclicCopyでprocessコピー
  - **102-109行目**: プロトタイプチェーンのコンストラクタ実行
  - **111行目**: process.env設定
  - **126-145行目**: features.require_moduleをfalseに設定

**主要処理フロー (deepCyclicCopy.ts)**:
- **10-13行目**: DeepCyclicCopyOptions型定義
- **15-30行目**: deepCyclicCopy関数
  - **21行目**: プリミティブ/Buffer判定
  - **23-24行目**: 循環参照チェック
  - **25-26行目**: 配列処理
  - **27-28行目**: オブジェクト処理
- **32-64行目**: deepCyclicCopyObject
- **66-87行目**: deepCyclicCopyArray

#### Step 3: Globマッチングを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | globsToMatcher.ts | `packages/jest-util/src/globsToMatcher.ts` | Globマッチング |

**主要処理フロー**:
- **13-16行目**: マッチャーキャッシュ（Map）
- **35-97行目**: globsToMatcher関数
  - **40-44行目**: 空配列時のショートカット
  - **46-61行目**: マッチャー作成とキャッシュ
  - **63-96行目**: マッチング関数
    - **71-73行目**: negativeカウント
    - **77-86行目**: マッチング結果の判定
    - **95行目**: 最終結果返却

#### Step 4: モジュール読み込みを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | requireOrImportModule.ts | `packages/jest-util/src/requireOrImportModule.ts` | CJS/ESM対応 |

**主要処理フロー**:
- **12-43行目**: importModule関数
  - **17行目**: pathToFileURLでURL変換
  - **20-22行目**: dynamic import実行
  - **28-31行目**: default exportチェック
- **45-74行目**: requireOrImportModule関数
  - **49-53行目**: 相対パスチェック
  - **55-57行目**: .mjs判定
  - **59-63行目**: require()で読み込み
  - **65-69行目**: ERR_REQUIRE_ESM/ERR_REQUIRE_ASYNC_MODULE時にimport

#### Step 5: ガベージコレクションを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 5-1 | garbage-collection-utils.ts | `packages/jest-util/src/garbage-collection-utils.ts` | メモリ管理 |

**主要処理フロー**:
- **12行目**: DELETION_MODE_SYMBOL定義
- **20行目**: PROTECT_SYMBOL定義
- **27行目**: DeletionMode型（'soft'\|'off'\|'on'）
- **35-53行目**: initializeGarbageCollectionUtils
- **61-73行目**: deleteProperties
- **86-127行目**: protectProperties
- **134-141行目**: canDeleteProperties
- **154-180行目**: deleteProperty（soft/on判定）
- **188-210行目**: emitAccessWarning（JEST-01警告）

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

```
jest-environment-node / jest-runtime
    │
    └─ jest-util
           │
           ├─ installCommonGlobals()
           │      ├─ createProcessObject()
           │      │      ├─ deepCyclicCopy()
           │      │      └─ createProcessEnv()
           │      ├─ initializeGarbageCollectionUtils()
           │      └─ deepCyclicCopy(globals)
           │
           ├─ globsToMatcher()
           │      └─ picomatch()
           │
           ├─ requireOrImportModule()
           │      ├─ require()
           │      └─ import()
           │
           ├─ deepCyclicCopy()
           │      ├─ deepCyclicCopyObject()
           │      └─ deepCyclicCopyArray()
           │
           └─ deleteProperties() / protectProperties()
                  └─ canDeleteProperties()
```

### データフロー図

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

Config.ConfigGlobals ───────┐
                           │
globalObject ──────────────┼──▶ installCommonGlobals() ──▶ 設定済みglobalObject
                           │          │
DeletionMode ──────────────┘          ├─▶ process (コピー)
                                      ├─▶ シンボル参照
                                      └─▶ GC初期化

Array<string> (globs) ─────▶ globsToMatcher() ──▶ Matcher関数
                                    │
                                    └─▶ picomatch(キャッシュ)

filePath ──────────────────▶ requireOrImportModule() ──▶ モジュール
                                    │
                                    ├─▶ require() (CJS)
                                    └─▶ import() (ESM)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/jest-util/src/index.ts` | ソース | エクスポート定義 |
| package.json | `packages/jest-util/package.json` | 設定 | パッケージ定義 |
| installCommonGlobals.ts | `packages/jest-util/src/installCommonGlobals.ts` | ソース | グローバル設定 |
| createProcessObject.ts | `packages/jest-util/src/createProcessObject.ts` | ソース | process作成 |
| deepCyclicCopy.ts | `packages/jest-util/src/deepCyclicCopy.ts` | ソース | ディープコピー |
| globsToMatcher.ts | `packages/jest-util/src/globsToMatcher.ts` | ソース | Globマッチング |
| requireOrImportModule.ts | `packages/jest-util/src/requireOrImportModule.ts` | ソース | モジュール読み込み |
| garbage-collection-utils.ts | `packages/jest-util/src/garbage-collection-utils.ts` | ソース | GCユーティリティ |
| formatTime.ts | `packages/jest-util/src/formatTime.ts` | ソース | 時間フォーマット |
| ErrorWithStack.ts | `packages/jest-util/src/ErrorWithStack.ts` | ソース | スタック付きエラー |
| preRunMessage.ts | `packages/jest-util/src/preRunMessage.ts` | ソース | 実行前メッセージ |
