# 機能設計書 25-@importの解決（substituteAtImports）

## 概要

本ドキュメントは、Tailwind CSSにおける`@import`および`@reference`ディレクティブの解決・インライン展開処理の仕様・処理フロー・内部構造を記述した機能設計書である。

### 本機能の処理概要

`@import`ディレクティブは、外部CSSスタイルシートを読み込みAST内にインライン展開する機能である。`@import "tailwindcss"`と記述すると、Tailwind CSSのスタイルシートが解決・読み込みされ、AST内に展開される。`@reference`ディレクティブは参照専用のインポートとして処理される。再帰的なインポートに対応し、layer/media/supports条件の付与もサポートする。

**業務上の目的・背景**：CSSの`@import`はスタイルシートの分割管理と再利用の基本的な仕組みである。Tailwind CSSではビルド時に`@import`を解決してインライン展開することで、ブラウザでの追加リクエストを避け、パフォーマンスを向上させる。`@reference`はスタイル定義の参照のみを行い、出力CSSには含めないユースケース（CSSモジュールでの@apply利用等）をサポートする。

**機能の利用シーン**：`@import "tailwindcss"`によるTailwind CSSの読み込み、`@import "./components.css"`によるカスタムスタイルシートの読み込み、`@import "./base.css" layer(base)`によるレイヤー付きインポート、`@reference "./globals.css"`によるスタイル参照（CSSモジュール向け）で使用される。

**主要な処理内容**：
1. ASTを走査し、`@import`および`@reference`ノードを検出する
2. ValueParserでインポートパラメータをパースし、URI・layer・media・supports条件を抽出する
3. loadStylesheet関数で外部スタイルシートを非同期に読み込む
4. 読み込んだCSSをパースし、再帰的にsubstituteAtImportsを適用する
5. layer/media/supports条件をアットルールでラップし、ASTに挿入する

**関連システム・外部連携**：CSSパーサー、ValueParser、loadStylesheet（外部から注入されるスタイルシート読み込み関数）と連携する。

**権限による制御**：特になし。CSS処理パイプラインの一部として自動的に実行される。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 1 | トップページ | 主機能 | index.cssの@import 'tailwindcss'ディレクティブを解決し、Tailwind CSSのスタイルシートをインライン展開する |
| 3 | レイアウト | 主機能 | globals.cssの@import 'tailwindcss'ディレクティブを解決し、Tailwind CSSのスタイルシートをインライン展開する |
| 4 | トップページ | 補助機能 | page.module.cssの@reference "./globals.css"により、globals.cssのスタイル定義を参照する |
| 5 | レイアウト | 主機能 | globals.cssの@importディレクティブ群を解決し、スタイルシートをインライン展開する |

## 機能種別

データ変換処理（スタイルシートのインライン展開）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| ast | AstNode[] | Yes | 処理対象のCSS AST | - |
| base | string | Yes | 相対パス解決のベースディレクトリ | - |
| loadStylesheet | LoadStylesheet | Yes | スタイルシート読み込み関数 | - |
| recurseCount | number | No | 再帰深度カウンタ（デフォルト0） | 100を超えるとエラー |
| track | boolean | No | ソースマップ追跡フラグ（デフォルトfalse） | - |

### 入力データソース

CSS ASTから`@import`および`@reference`アットルールノードが抽出される。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| features | Features | Features.AtImportフラグを含むビットフラグ |

### 出力先

AST上の`@import`/`@reference`ノードが読み込まれたスタイルシートのASTに直接置換される。

## 処理フロー

### 処理シーケンス

```
1. ASTを走査して@importおよび@referenceノードを検出
   └─ walk(ast, callback)
2. インポートパラメータをパース
   └─ parseImportParams(ValueParser.parse(node.params))
3. @referenceの場合はmediaを'reference'に設定
4. URI検証（data:, http://, https://はスキップ）
5. contextノードを作成（プレースホルダー）
6. 非同期でスタイルシートを読み込み
   └─ loadStylesheet(uri, base)
7. 読み込んだCSSをパース
   └─ CSS.parse(loaded.content)
8. 再帰的にsubstituteAtImportsを適用
   └─ substituteAtImports(ast, loaded.base, loadStylesheet, recurseCount + 1)
9. layer/media/supports条件でラップ
   └─ buildImportNodes(node, ast, layer, media, supports)
10. contextノードにノードを設定
    └─ contextNode.nodes = buildImportNodes(...)
```

### フローチャート

```mermaid
flowchart TD
    A[substituteAtImports開始] --> B[ASTをwalk]
    B --> C{@import/@reference?}
    C -->|No| D[スキップ]
    C -->|Yes| E[parseImportParamsでパラメータ解析]
    E --> F{パース成功?}
    F -->|No| D
    F -->|Yes| G{data:/http:/https:?}
    G -->|Yes| D
    G -->|No| H{recurseCount > 100?}
    H -->|Yes| I[再帰上限エラー]
    H -->|No| J[loadStylesheetで読み込み]
    J --> K[CSS.parseでパース]
    K --> L[再帰的にsubstituteAtImports]
    L --> M[buildImportNodesでラップ]
    M --> N[contextNodeに設定]
    N --> O[WalkAction.ReplaceSkip]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | data: URIスキップ | `data:`で始まるURIはインライン展開しない | URI検証時 |
| BR-02 | リモートURIスキップ | `http://`または`https://`で始まるURIはインライン展開しない | URI検証時 |
| BR-03 | 再帰上限 | 再帰深度が100を超えるとエラー | recurseCount > 100 |
| BR-04 | @reference処理 | `@reference`はmediaを'reference'に設定して処理される | @referenceノード検出時 |
| BR-05 | url()関数スキップ | `url()`関数形式のインポートはインライン展開しない | parseImportParams内 |
| BR-06 | layer/supports順序 | layer()はsupports()より前に記述する必要がある | parseImportParams内 |
| BR-07 | クォート必須 | インポートパスはシングルまたはダブルクォートで囲む必要がある | parseImportParams内 |

### 計算ロジック

特段の計算ロジックはない。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | Error | 再帰深度が100を超えた | 循環インポートを解消する |
| - | Error | layer()がsupports()の後に記述された | layer()をsupports()の前に移動する |

### リトライ仕様

リトライは行わない。

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

トランザクション管理は不要。非同期処理はPromise.allで並行実行される。

## パフォーマンス要件

- 複数の@importを持つ場合、Promise.allで並行して読み込みを実行する
- WalkAction.ReplaceSkipにより、解決済みのサブツリーの再走査をスキップする

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

- リモートURL（http/https）のインポートは自動的にスキップされ、外部リソースの読み込みは行われない
- data: URIもスキップされる

## 備考

- parseImportParams関数はpostcss-importライブラリの`parse-statements`を修正・インラインしたものである
- `@reference`は`@import`と同じ仕組みで処理されるが、mediaが'reference'に設定されることでスタイル出力への影響が制御される
- 非同期処理（async/await）を使用しており、loadStylesheetは外部から注入される

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | at-import.ts | `packages/tailwindcss/src/at-import.ts` | **7-14行目**: LoadStylesheet型の定義。path、base、contentを返す非同期関数 |

**読解のコツ**: `LoadStylesheet`は外部から注入されるI/O関数であり、ビルドツール統合レイヤー（Vite/PostCSS/Webpack/CLI）がそれぞれ実装を提供する。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | at-import.ts | `packages/tailwindcss/src/at-import.ts` | **16-81行目**: substituteAtImports関数の全体 |

**主要処理フロー**:
1. **26-27行目**: @importと@referenceノードの検出
2. **28行目**: parseImportParamsでパラメータ解析
3. **30-32行目**: @referenceの場合はmedia='reference'に設定
4. **39-40行目**: data:とリモートURIのスキップ
5. **50-53行目**: 再帰上限チェック（100回）
6. **56-58行目**: loadStylesheetでの読み込みとCSS.parseでのパース
7. **58行目**: 再帰的なsubstituteAtImportsの適用
8. **60-66行目**: buildImportNodesでのlayer/media/supportsラップ
9. **72行目**: WalkAction.ReplaceSkipでノード置換
10. **76-78行目**: Promise.allで非同期処理を待機

#### Step 3: パラメータパースを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | at-import.ts | `packages/tailwindcss/src/at-import.ts` | **87-148行目**: parseImportParams関数 |

**主要処理フロー**:
- **98-104行目**: URI（クォート付き文字列）の抽出
- **106-111行目**: url()関数の場合はnullを返してスキップ
- **115-133行目**: layer()の解析
- **135-139行目**: supports()の解析
- **141-142行目**: 残りをmedia条件として解析

#### Step 4: インポートノード構築を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | at-import.ts | `packages/tailwindcss/src/at-import.ts` | **150-178行目**: buildImportNodes関数 |

**主要処理フロー**:
- **159-163行目**: layer条件の@layerラップ
- **165-169行目**: media条件の@mediaラップ
- **171-175行目**: supports条件の@supportsラップ

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

```
substituteAtImports(ast, base, loadStylesheet, recurseCount, track)
    │
    ├─ walk(ast, callback)
    │      │
    │      ├─ parseImportParams(ValueParser.parse(node.params))
    │      │      └─ ValueParser.toCss(node.nodes)
    │      │
    │      ├─ loadStylesheet(uri, base)  -- 非同期I/O
    │      │
    │      ├─ CSS.parse(loaded.content)
    │      │
    │      ├─ substituteAtImports(ast, loaded.base, ...)  -- 再帰呼び出し
    │      │
    │      └─ buildImportNodes(node, ast, layer, media, supports)
    │             └─ atRule('@layer'/'@media'/'@supports', ...)
    │
    └─ Promise.all(promises)
```

### データフロー図

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

AstNode[]              ──▶ 1. @import/@reference検出      ──▶ AstNode[]（展開済み）
(@import含むCSS AST)         │                                 + Features.AtImport
                             ├─ parseImportParams
                             │    でURI/layer/media/supports抽出
                             │
                             ├─ loadStylesheet(uri, base)
                             │    で外部ファイル読み込み
                             │
                             ├─ CSS.parse
                             │    でCSS→AST変換
                             │
                             ├─ substituteAtImports (再帰)
                             │    でネストされた@importを解決
                             │
                             └─ buildImportNodes
                                  でlayer/media/supportsラップ
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| at-import.ts | `packages/tailwindcss/src/at-import.ts` | ソース | @import解決の主要実装 |
| css-parser.ts | `packages/tailwindcss/src/css-parser.ts` | ソース | CSSパーサー |
| value-parser.ts | `packages/tailwindcss/src/value-parser.ts` | ソース | インポートパラメータのパース |
| ast.ts | `packages/tailwindcss/src/ast.ts` | ソース | atRule, context等のAST操作 |
| walk.ts | `packages/tailwindcss/src/walk.ts` | ソース | AST走査ユーティリティ |
| index.ts | `packages/tailwindcss/src/index.ts` | ソース | コンパイルパイプラインからsubstituteAtImportsを呼び出す |
