# 機能設計書 67-モジュール

## 概要

本ドキュメントは、CoffeeScriptのモジュール（ES6 import/export）機能の設計を記述する。ES2015のモジュールシステムを完全にサポートし、モジュールのインポートとエクスポートを可能にする言語機能である。

### 本機能の処理概要

CoffeeScriptのモジュール機能は、ES2015で導入されたimport/export構文をネイティブにサポートする。名前付きエクスポート、デフォルトエクスポート、名前空間インポート、再エクスポートなど、ES2015モジュールの全機能を利用可能である。また、import assertionsもサポートしている。

**業務上の目的・背景**：
モダンなJavaScript開発では、コードをモジュールに分割して管理することが標準的である。CoffeeScriptもES2015モジュール構文をサポートすることで、既存のJavaScriptエコシステムとの互換性を維持し、Webpack、Rollup、Node.js ESMなどのモジュールバンドラー/ローダーとシームレスに連携できる。

**機能の利用シーン**：
- 名前付きインポート（例：`import { a, b } from 'module'`）
- デフォルトインポート（例：`import React from 'react'`）
- 名前空間インポート（例：`import * as utils from './utils'`）
- 名前付きエクスポート（例：`export { foo, bar }`）
- デフォルトエクスポート（例：`export default class App`）
- 再エクスポート（例：`export { x } from 'other'`）
- Import assertions（例：`import data from './data.json' assert { type: 'json' }`）

**主要な処理内容**：
1. `import`文の解析とImportDeclarationノード生成
2. `export`文の解析とExportDeclarationノード生成
3. ImportClause（デフォルト/名前付き/名前空間）の解析
4. ExportSpecifierList、ImportSpecifierListの解析
5. スコープへのインポートシンボル登録
6. 重複インポートのエラーチェック
7. トップレベル制約のチェック

**関連システム・外部連携**：
モジュール構文はgrammar.coffeeのImport/Export規則で解析され、対応するノードクラス群（ImportDeclaration、ExportDeclaration等）としてASTに組み込まれる。出力されるJavaScriptはES2015モジュール構文となり、モジュールバンドラーやNode.js ESMで処理される。

**権限による制御**：
本機能はコンパイル時の言語機能であり、権限による制御は適用されない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面関連なし（言語機能） |

## 機能種別

言語構文変換 / モジュール管理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| clause | ImportClause/ExportSpecifierList | No | インポート/エクスポートの詳細 | - |
| source | StringLiteral | Yes（インポート時） | モジュールパス | 補間文字列は不可 |
| assertions | Obj | No | import assertions | - |

### 入力データソース

CoffeeScriptソースコード内の`import`/`export`文

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| JavaScript | String | ES2015 import/export文 |

### 出力先

JavaScriptコード（標準出力またはファイル）

## 処理フロー

### 処理シーケンス

```
1. import/export文の解析
   └─ grammar.coffeeのImport/Export規則でトークン列を解析
2. ノード生成
   └─ ImportDeclaration/ExportDeclarationノードを生成
3. バリデーション
   └─ 3.1 モジュールパスが補間文字列でないことを確認
   └─ 3.2 トップレベルスコープであることを確認
   └─ 3.3 インポートシンボルの重複をチェック
4. スコープ処理
   └─ インポートされたシンボルをスコープに登録
5. コンパイル処理
   └─ ES2015構文でJavaScriptを生成
```

### フローチャート

```mermaid
flowchart TD
    A[import/export文の開始] --> B{import or export?}
    B -->|import| C[ImportDeclaration生成]
    B -->|export| D[ExportDeclaration生成]
    C --> E{clause タイプ}
    E -->|default| F[ImportDefaultSpecifier]
    E -->|namespace *| G[ImportNamespaceSpecifier]
    E -->|named {}| H[ImportSpecifierList]
    E -->|side-effect| I[副作用インポートのみ]
    D --> J{export タイプ}
    J -->|default| K[ExportDefaultDeclaration]
    J -->|named| L[ExportNamedDeclaration]
    J -->|all *| M[ExportAllDeclaration]
    F --> N[スコープ登録]
    G --> N
    H --> N
    K --> O[コンパイル]
    L --> O
    M --> O
    N --> P{重複チェック}
    P -->|重複あり| Q[エラー: already declared]
    P -->|OK| O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-67-1 | トップレベル制約 | import/exportはファイルのトップレベルでのみ使用可能 | indent.length !== 0 の場合エラー |
| BR-67-2 | モジュールパス制約 | sourceは補間なしの文字列である必要がある | StringWithInterpolationsの場合エラー |
| BR-67-3 | インポート重複禁止 | 同一シンボルを複数回インポート不可 | 同名のシンボルがimportedSymbolsに存在 |
| BR-67-4 | 匿名クラスエクスポート禁止 | export defaultでない限り、匿名クラスはエクスポート不可 | Class.variableがない場合 |
| BR-67-5 | read-only制約 | インポートされたシンボルへの代入は禁止 | 代入時にスコープタイプが'import'の場合 |

### 計算ロジック

- シンボル登録: `o.scope.add name.value, @moduleDeclarationType`
- 重複チェック: `@identifier in o.importedSymbols or o.scope.check(@identifier)`

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

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

本機能はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SyntaxError | 構文エラー | import/export statements must be at top-level scope | トップレベルに移動 |
| SyntaxError | 構文エラー | module name must be an uninterpolated string | 補間なしの文字列を使用 |
| SyntaxError | 構文エラー | 'X' has already been declared | 重複するインポートを削除 |
| SyntaxError | 構文エラー | anonymous classes cannot be exported | クラスに名前を付ける |
| SyntaxError | 構文エラー | 'X' is read-only | インポートシンボルへの代入を削除 |

### リトライ仕様

コンパイル時エラーのため、リトライは適用されない。

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

本機能はデータベーストランザクションを使用しない。

## パフォーマンス要件

- コンパイル時間: インポート/エクスポートの数に比例
- モジュール解決: バンドラー/ローダーの責務

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

- 動的importはセキュリティリスクがある場合あり（機能No.70参照）
- 信頼できないモジュールのインポートに注意

## 備考

- ES2015モジュールの完全サポート
- CommonJS（`require`/`module.exports`）はCoffeeScript構文としては未サポート（JavaScriptとして使用可能）
- import.metaもサポート

---

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

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

### 推奨読解順序

#### Step 1: 文法定義を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | grammar.coffee | `src/grammar.coffee` | Import規則（483-498行目）、Export規則（523-541行目） |

**読解のコツ**:
- 483-498行目: 様々なimport構文パターン
- 523-541行目: 様々なexport構文パターン
- ASSERT Objectでimport assertionsをサポート

**主要処理フロー**:
1. **484行目**: `IMPORT String` - 副作用インポート
2. **486行目**: `IMPORT ImportDefaultSpecifier FROM String` - デフォルトインポート
3. **488行目**: `IMPORT ImportNamespaceSpecifier FROM String` - 名前空間インポート
4. **492行目**: `IMPORT { ImportSpecifierList } FROM String` - 名前付きインポート
5. **533行目**: `EXPORT DEFAULT Expression` - デフォルトエクスポート
6. **535行目**: `EXPORT EXPORT_ALL FROM String` - 全エクスポート

#### Step 2: ノードクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | nodes.coffee | `src/nodes.coffee` | ModuleDeclaration、ImportDeclaration、ExportDeclaration（3209-3476行目） |

**主要処理フロー**:
- **3209行目**: `class ModuleDeclaration extends Base` - 基底クラス
- **3220-3230行目**: `checkSource`と`checkScope`メソッド
- **3240行目**: `class ImportDeclaration extends ModuleDeclaration`
- **3297行目**: `class ExportDeclaration extends ModuleDeclaration`
- **3334行目**: `class ExportNamedDeclaration`
- **3349行目**: `class ExportDefaultDeclaration`
- **3355行目**: `class ExportAllDeclaration`

#### Step 3: Specifierクラスを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | nodes.coffee | `src/nodes.coffee` | ModuleSpecifier、ImportSpecifier、ExportSpecifier（3390-3457行目） |

**読解のコツ**:
- ImportSpecifierでは重複チェックを実行
- `addIdentifierToScope`でスコープにシンボルを登録

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

```
CoffeeScript.compile()
    │
    ├─ Lexer.tokenize()
    │      ├─ IMPORTトークン
    │      ├─ EXPORTトークン
    │      └─ FROMトークン
    │
    ├─ parser.parse()
    │      ├─ Import規則
    │      │      ├─ ImportDeclaration
    │      │      ├─ ImportClause
    │      │      └─ ImportSpecifierList
    │      └─ Export規則
    │             ├─ ExportNamedDeclaration
    │             ├─ ExportDefaultDeclaration
    │             └─ ExportAllDeclaration
    │
    └─ compileNode()
           ├─ checkScope() - トップレベル確認
           ├─ addIdentifierToScope() - スコープ登録
           └─ ES2015構文出力
```

### データフロー図

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

CoffeeScript           Lexer           Parser              Compiler
import/export      →  トークン列  →   Declaration    →    JavaScript
                                    ノード              ES2015構文

例:
import { foo, bar } from 'module'
    ↓
[IMPORT, '{', IDENTIFIER, ',', IDENTIFIER, '}', FROM, STRING]
    ↓
ImportDeclaration {
  clause: ImportClause {
    namedImports: ImportSpecifierList([
      ImportSpecifier('foo'),
      ImportSpecifier('bar')
    ])
  },
  source: StringLiteral('module')
}
    ↓
import { foo, bar } from 'module';
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| grammar.coffee | `src/grammar.coffee` | ソース | Import（483-520行目）、Export（523-557行目）規則 |
| nodes.coffee | `src/nodes.coffee` | ソース | ModuleDeclaration関連クラス（3209-3476行目） |
| lexer.coffee | `src/lexer.coffee` | ソース | IMPORT、EXPORT、FROM、AS、DEFAULTトークン |
| scope.litcoffee | `src/scope.litcoffee` | ソース | インポートシンボルのスコープ管理 |
