# 機能設計書 33-module

## 概要

本ドキュメントは、Node.js の `module` モジュール（モジュールシステムAPI）の機能設計書である。このモジュールは、CommonJS (CJS) および ECMAScript Modules (ESM) の両方のモジュールシステムを管理し、モジュールの読み込み、解決、キャッシュに関する機能を提供する。

### 本機能の処理概要

module モジュールは、Node.js のモジュールシステムの中核を担い、`require()` 関数の動作やモジュール解決アルゴリズムを制御する。ESMローダーの登録、ソースマップサポート、コンパイルキャッシュ、TypeScriptの型除去など、高度なモジュール関連機能へのアクセスも提供する。

**業務上の目的・背景**：Node.js アプリケーションはモジュールシステムを通じてコードを構造化する。このモジュールは、カスタムローダーの登録、組み込みモジュールの一覧取得、ソースマップの管理など、モジュールシステムを拡張・カスタマイズするためのAPIを提供する。

**機能の利用シーン**：
- カスタムモジュールローダーの登録（ESMフック）
- 組み込みモジュール一覧の取得
- ソースマップの検索・管理
- コンパイルキャッシュの有効化・管理
- TypeScriptコードの型除去
- package.json の検索

**主要な処理内容**：
1. モジュールの解決とロード（`require()`）
2. ESMローダーフックの登録（`register()`）
3. ソースマップの管理（`findSourceMap()` / `SourceMap`）
4. コンパイルキャッシュの管理（`enableCompileCache()` / `flushCompileCache()`）
5. package.json の検索（`findPackageJSON()`）
6. TypeScript型除去（`stripTypeScriptTypes()`）

**関連システム・外部連携**：
- V8 エンジン（コンパイルキャッシュ）
- ファイルシステム（モジュール読み込み）
- ソースマップ（デバッグサポート）

**権限による制御**：特段の権限制御は存在しない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | CLIツールのため画面なし |

## 機能種別

モジュール管理 / ローダー制御 / キャッシュ管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| specifier | string | Yes | モジュール指定子（パスまたはパッケージ名） | 文字列であること |
| parentURL | string \| URL | No | 親モジュールのURL | URL形式 |
| data | object | No | ローダー初期化データ | オブジェクトであること |
| transferList | Array | No | 転送可能オブジェクトリスト | 配列であること |
| cacheDir | string | No | コンパイルキャッシュディレクトリ | 有効なパス |

### 入力データソース

- ファイルシステム（.js、.mjs、.cjs、.json ファイル）
- URL（ESM モジュール）
- コマンドライン引数（--conditions、--experimental-loader等）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| module.exports | any | require() で読み込んだモジュールのエクスポート |
| builtinModules | string[] | 組み込みモジュールの一覧 |
| SourceMap | class | ソースマップクラス |

### 出力先

- モジュールキャッシュ（`Module._cache`）
- グローバルスコープ（require によるモジュール読み込み）

## 処理フロー

### 処理シーケンス

```
1. require(specifier) 呼び出し
   └─ Module._load() でモジュール解決開始
2. パス解決
   └─ Module._resolveFilename() でファイルパスを特定
3. キャッシュ確認
   └─ Module._cache にあれば即座に返却
4. モジュールインスタンス作成
   └─ new Module(filename, parent)
5. ファイル読み込み・コンパイル
   └─ Module._compile() でJavaScriptとして実行
6. exports の返却
   └─ module.exports をrequire()の戻り値として返却
```

### フローチャート

```mermaid
flowchart TD
    A[require/specifier] --> B{キャッシュ確認}
    B -->|Hit| C[キャッシュから返却]
    B -->|Miss| D[パス解決]
    D --> E{ファイル存在?}
    E -->|No| F[MODULE_NOT_FOUND エラー]
    E -->|Yes| G[Module インスタンス作成]
    G --> H[キャッシュに登録]
    H --> I[ファイル読み込み]
    I --> J{ファイル種別}
    J -->|.js| K[JavaScript コンパイル]
    J -->|.json| L[JSON パース]
    J -->|.node| M[ネイティブアドオン読み込み]
    K --> N[module.exports 返却]
    L --> N
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | キャッシュ優先 | 同一モジュールは一度だけロードされキャッシュされる | require()呼び出し時 |
| BR-02 | 拡張子推論 | .js、.json、.node の順で拡張子を補完する | 拡張子なし指定時 |
| BR-03 | node_modules 検索 | 相対パス以外は node_modules を上位ディレクトリまで検索 | パッケージ名指定時 |
| BR-04 | 循環依存解決 | 循環参照時は部分的なexportsオブジェクトを返却 | 循環参照発生時 |

### 計算ロジック

モジュール解決アルゴリズム:
1. コアモジュールチェック
2. 相対パス → 絶対パス変換
3. node_modules 検索（親ディレクトリを順次遡上）
4. package.json の main/exports フィールド参照

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

該当なし

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

該当なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| MODULE_NOT_FOUND | Error | 指定モジュールが見つからない | パス・パッケージ名を確認 |
| ERR_INVALID_ARG_TYPE | TypeError | 引数の型が不正 | 正しい型を渡す |
| ERR_REQUIRE_ESM | Error | CJSからESMをrequire | import()を使用 |

### リトライ仕様

リトライは行わない。

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

該当なし

## パフォーマンス要件

- モジュールキャッシュにより、同一モジュールの重複ロードを防止
- コンパイルキャッシュにより、V8コンパイル結果を永続化して起動を高速化

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

- require() は任意のコードを実行可能なため、信頼できるソースのみ使用すること
- カスタムローダーの登録は慎重に行うこと

## 備考

- `module.builtinModules` で組み込みモジュール一覧を取得可能
- `--experimental-require-module` でESMをrequire可能（実験的）
- `NODE_V8_COVERAGE` 環境変数でコードカバレッジを有効化可能

---

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

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

### 推奨読解順序

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

まず、Moduleクラスの公開APIを理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | module.js | `lib/module.js` | 公開APIの構造 |

**読解のコツ**: `module.js` は `internal/modules/cjs/loader.js` の Module クラスを拡張して公開APIを提供するラッパー。

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

モジュールのエクスポートと各機能の追加を把握する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | module.js | `lib/module.js` | Module クラスのインポート（8行目） |
| 2-2 | module.js | `lib/module.js` | register 関数の追加（24行目） |
| 2-3 | module.js | `lib/module.js` | ソースマップAPI追加（32-36行目） |

**主要処理フロー**:
1. **4-7行目**: ソースマップ関連のインポート
2. **8行目**: CJSローダーからModuleクラスをインポート
3. **9行目**: ESMローダーから register 関数をインポート
4. **14-18行目**: ヘルパー関数のインポート
5. **24-30行目**: Module への各種API追加

#### Step 3: CJSローダーの実装を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | loader.js | `lib/internal/modules/cjs/loader.js` | Module クラス定義 |
| 3-2 | loader.js | `lib/internal/modules/cjs/loader.js` | module.exports（115-132行目） |

**主要処理フロー**:
- **80-112行目**: 内部シンボル定義（kModuleSource、kModuleExport等）
- **115-132行目**: module.exports で公開するAPI

#### Step 4: ヘルパー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | helpers.js | `lib/internal/modules/helpers.js` | makeRequireFunction（144行目〜） |
| 4-2 | helpers.js | `lib/internal/modules/helpers.js` | loadBuiltinModule（117-127行目） |
| 4-3 | helpers.js | `lib/internal/modules/helpers.js` | コンパイルキャッシュ関連（36-41行目） |

**主要処理フロー**:
- **61-65行目**: toRealPath - シンボリックリンクの解決
- **76-92行目**: initializeCjsConditions - CJS条件の初期化
- **117-127行目**: loadBuiltinModule - 組み込みモジュールのロード
- **144-150行目**: makeRequireFunction - require関数の作成

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

```
require(specifier)
    │
    ├─ Module._load(request, parent, isMain)
    │      ├─ Module._resolveFilename(request, parent, isMain)
    │      │      ├─ BuiltinModule.canBeRequiredByUsers(request)
    │      │      └─ Module._findPath(request, paths)
    │      │
    │      ├─ Module._cache[filename] 確認
    │      │
    │      └─ new Module(filename, parent)
    │             └─ module.load(filename)
    │                    └─ Module._extensions[ext](module, filename)
    │                           └─ module._compile(content, filename)
    │
    └─ module.exports 返却

Module.register(specifier, parentURL, options)
    │
    └─ internal/modules/esm/loader.register()
           └─ ESMローダーフック登録
```

### データフロー図

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

require('fs') ─────────▶ BuiltinModule.map.get('fs') ──▶ fs モジュール
                               │
require('./app') ──────▶ Module._resolveFilename() ────▶ 絶対パス
      │                        │
      ▼                        ▼
ファイル内容 ─────────▶ Module._compile() ────────────▶ module.exports
                               │
                               ▼
                        Module._cache[path] 登録
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| module.js | `lib/module.js` | ソース | 公開APIラッパー |
| loader.js | `lib/internal/modules/cjs/loader.js` | ソース | CJSローダー本体 |
| helpers.js | `lib/internal/modules/helpers.js` | ソース | ヘルパー関数群 |
| loader.js | `lib/internal/modules/esm/loader.js` | ソース | ESMローダー |
| source_map_cache.js | `lib/internal/source_map/source_map_cache.js` | ソース | ソースマップキャッシュ |
| source_map.js | `lib/internal/source_map/source_map.js` | ソース | ソースマップクラス |
| package_json_reader.js | `lib/internal/modules/package_json_reader.js` | ソース | package.json 読み込み |
| typescript.js | `lib/internal/modules/typescript.js` | ソース | TypeScript型除去 |
