# 機能設計書 57-@babel/plugin-transform-json-modules

## 概要

本ドキュメントは、Babelプラグイン `@babel/plugin-transform-json-modules` の機能設計を記載したものである。本プラグインは、JSONモジュールインポート（`import data from './data.json' with { type: 'json' }`）をブラウザおよびNode.jsで動作するコードに変換する。

### 本機能の処理概要

**業務上の目的・背景**：JSONモジュールインポートは、Import Attributes提案（`with { type: 'json' }`）を使用してJSONファイルを直接ESモジュールとしてインポートする機能である。この構文は、セキュリティ上の理由（MIME type混同攻撃の防止）と明示性のために導入された。しかし、すべての環境でこの構文がサポートされているわけではないため、トランスパイルが必要となる。本プラグインは、ターゲット環境に応じて適切なJSON読み込みコードに変換する。

**機能の利用シーン**：
- JSONファイル（設定ファイル、データファイルなど）をESモジュールとしてインポートする場合
- ブラウザ環境でfetch APIを使用してJSONを読み込む場合
- Node.js環境でfs.readFileSyncを使用してJSONを読み込む場合
- CommonJSにコンパイルする場合にrequireを使用する場合

**主要な処理内容**：
1. `with { type: 'json' }` 属性を持つImportDeclarationを検出
2. ターゲット環境とモジュール出力形式を判定
3. 環境に応じた適切なJSONフェッチコードを生成
4. 元のインポート宣言を削除し、変換後のコードで置換

**関連システム・外部連携**：`@babel/helper-import-to-platform-api` を使用してプラットフォーム固有のAPIコードを生成。CommonJS、Web fetch、Node.js fsなど複数の環境をサポート。

**権限による制御**：本プラグインに権限制御の概念は存在しない。

## 関連画面

該当なし（CLIツール/ビルドツールとして動作）

## 機能種別

データ変換処理（ASTトランスフォーム）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| uncheckedRequire | boolean | No | CommonJS環境でrequireを直接使用するか | boolean型のみ許可 |

### 入力データソース

- Babelコアから渡されるAST（抽象構文木）
- `ImportDeclaration` ノードで `attributes` に `type: 'json'` を持つもの

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 変換後AST | AST Node | 環境に応じたJSON読み込みコード |

### 出力先

変換されたASTはBabelコアに返され、最終的にJavaScriptコードとして出力される

## 処理フロー

### 処理シーケンス

```
1. プラグイン初期化
   └─ Babelバージョン検証（^7.22.0 || ^8.0.0）
   └─ uncheckedRequireオプション取得

2. Program Visitor
   └─ sourceType === "module" の場合のみ
   └─ ヘルパー関数取得（getHelper）

3. ImportDeclaration検出
   └─ attributes に type: 'json' があるか判定
   └─ phase modifier があればエラー
   └─ 追加の属性があればエラー
   └─ named imports があればエラー

4. 環境判定と変換
   └─ CommonJS: require() または fetch
   └─ Web: fetch().then(r => r.json())
   └─ Node.js (sync): JSON.parse(fs.readFileSync())
   └─ Node.js (async): JSON.parse

5. インポート宣言の削除と置換
   └─ 元の宣言を削除
   └─ 並列静的インポートを生成
```

### フローチャート

```mermaid
flowchart TD
    A[ImportDeclaration検出] --> B{type: 'json' 属性?}
    B -->|No| Z[スキップ]
    B -->|Yes| C{エラーチェック}
    C -->|phase modifier| E1[エラー]
    C -->|named imports| E2[エラー]
    C -->|追加属性| E3[エラー]
    C -->|OK| D{出力形式?}
    D -->|CommonJS| F[require/fetch]
    D -->|ESM| G{ターゲット環境?}
    G -->|Web| H[fetch().then]
    G -->|Node sync| I[JSON.parse(readFile)]
    G -->|Node async| J[JSON.parse]
    F --> K[宣言置換]
    H --> K
    I --> K
    J --> K
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | type属性必須 | `with { type: 'json' }` が必要 | JSONインポート |
| BR-02 | phase modifier禁止 | `import defer` などは使用不可 | JSONインポート |
| BR-03 | 単一属性のみ | type以外の属性は許可されない | JSONインポート |
| BR-04 | named imports禁止 | `import { x } from` は使用不可 | JSONインポート |
| BR-05 | namespace handling | namespace importはdefaultでラップ | `import * as ns` |

### 計算ロジック

変換方法はターゲット環境と出力モジュール形式によって決定：
- CommonJS + uncheckedRequire: `require(specifier)`
- Web: `fetch(url).then(r => r.json())`
- Node.js sync: `JSON.parse(fs.readFileSync(path))`
- Node.js async: `JSON.parse` をthenで呼び出し

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

該当なし（データベース操作は行わない）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | CodeFrameError | phase modifier使用 | "JSON modules do not support phase modifiers." |
| - | CodeFrameError | 追加属性使用 | "Unknown attribute for JSON modules." |
| - | CodeFrameError | named imports使用 | "JSON modules do not support named imports." |
| - | Error | 非対応モジュール形式 | "can only be used when not compiling modules, or when compiling them to CommonJS" |

### リトライ仕様

該当なし

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

該当なし（ステートレスな変換処理）

## パフォーマンス要件

- `buildParallelStaticImports` により複数のJSONインポートを並列化
- 非同期環境では Promise.all で並列フェッチ

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

- type属性による明示的なタイプ指定でMIME type混同攻撃を防止
- JSONインポートはデフォルトエクスポートのみ許可

## 備考

- JSONモジュール提案をネイティブサポートする環境ではこのプラグインは不要
- `@babel/preset-env` 使用時は、ターゲット環境に応じて自動的に適用される
- AMD、UMD、SystemJSへのモジュール変換との組み合わせは未サポート

---

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

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

### 推奨読解順序

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

プラグインで使用されるオプションと型を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/babel-plugin-transform-json-modules/src/index.ts` | Options インターフェース（10-12行目） |

**読解のコツ**: `uncheckedRequire` オプションはCommonJS環境でrequireを直接使用するかどうかを制御。

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

プラグインの初期化とヘルパー取得を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `packages/babel-plugin-transform-json-modules/src/index.ts` | プラグイン初期化（14-47行目） |

**主要処理フロー**:
1. **14-16行目**: プラグイン宣言、template取得
2. **18行目**: ターゲット環境取得
3. **20-21行目**: ESM/CJSヘルパーキャッシュ
4. **23-33行目**: transformers定義（CommonJS, webFetch, nodeFsSync, nodeFsAsync）
5. **35-47行目**: getHelper関数でモジュール形式に応じたヘルパー取得

#### Step 3: インポート変換ロジックを理解する

JSONインポートの検出と変換処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.ts | `packages/babel-plugin-transform-json-modules/src/index.ts` | Program Visitor（65-122行目） |

**主要処理フロー**:
- **49-51行目**: getAttributeKey関数で属性キー取得
- **53-59行目**: hasTypeJson関数でtype:json判定
- **66行目**: モジュール以外はスキップ
- **71-88行目**: エラーチェック（phase, 追加属性, named imports）
- **103-113行目**: namespace importの場合のdefaultラップ
- **116行目**: 元のimport宣言を削除
- **120-121行目**: buildParallelStaticImportsで並列インポート生成

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

```
@babel/plugin-transform-json-modules
    │
    ├─ getHelper(file)
    │      └─ importToPlatformApi()
    │             └─ CommonJS / ESM ヘルパー選択
    │
    └─ visitor.Program()
           │
           ├─ hasTypeJson(): type: 'json' チェック
           │
           ├─ エラーチェック
           │      ├─ phase modifier
           │      ├─ 追加属性
           │      └─ named imports
           │
           ├─ helper.buildFetch(): フェッチコード生成
           │
           └─ buildParallelStaticImports()
                  └─ 並列インポート宣言生成
```

### データフロー図

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

import data from                 AST解析  ───▶  Visitor  ───▶  const data = await
  './data.json'                                    │             fetch(new URL(
  with { type: 'json' };                           │               './data.json',
                                             hasTypeJson            import.meta.url
                                                   │             )).then(r => r.json());
                                             buildFetch
                                                   │
                                        buildParallelStaticImports
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/babel-plugin-transform-json-modules/src/index.ts` | ソース | プラグインエントリーポイント |
| package.json | `packages/babel-plugin-transform-json-modules/package.json` | 設定 | パッケージ定義、依存関係 |
| index.ts | `packages/babel-helper-import-to-platform-api/src/index.ts` | ソース | プラットフォームAPIへの変換ヘルパー |
