# 機能設計書 55-統計出力フォーマット

## 概要

本ドキュメントは、webpackにおける統計出力フォーマット機能（DefaultStatsPrinterPlugin / StatsPrinter）の設計仕様を記述する。StatsFactory（No.54）で生成された統計オブジェクトを人間可読なテキスト形式に整形し、CLI出力やファイル出力を行う機能である。

### 本機能の処理概要

**業務上の目的・背景**：webpackのビルド結果を開発者が理解するためには、統計オブジェクトを見やすく整形して出力する必要がある。StatsPrinterはHookMapベースのプラグインアーキテクチャにより、各統計要素（アセット、モジュール、チャンク、エラー等）を適切なフォーマットで文字列に変換する。色付け、サイズ表示、時間表示等のフォーマッタも提供する。

**機能の利用シーン**：webpack CLI実行時のコンソール出力、webpack-dev-serverのターミナル表示、stats.toString()メソッドによる文字列化に利用される。

**主要な処理内容**：
1. 統計オブジェクトを再帰的に走査し、各要素をフックベースで文字列に変換する
2. オブジェクト型の場合はプロパティの要素として展開し、printElementsフックで結合する
3. 配列型の場合は各アイテムを変換し、printItemsフックで結合する
4. プリミティブ値の場合はprintフックで直接文字列に変換する
5. resultフックで最終的な文字列を返却する

**関連システム・外部連携**：StatsFactory（No.54）が生成したStatsCompilationオブジェクトを入力とする。DefaultStatsPrinterPluginがフォーマットロジックを提供する。

**権限による制御**：特になし。stats設定のcolorsオプションで色付けを制御する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 本機能はUIを持たない内部処理であり、直接関連する画面は存在しない |

## 機能種別

データ変換処理 / レポート出力

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| type | string | Yes | 出力対象の型名（"compilation", "asset"等） | StatsPrinter内部で解決 |
| object | any | Yes | 出力対象データ（StatsCompilation等） | - |
| baseContext | StatsPrinterContext | No | フォーマッタ・色関数等のコンテキスト | - |

### 入力データソース

- StatsCompilationオブジェクト: StatsFactory.create()で生成された統計データ
- StatsPrinterContext: formatSize, formatTime, bold, red等のフォーマットユーティリティ

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | string \| undefined | 整形された統計文字列 |

### 出力先

コンソール出力（process.stdout）またはstats.toString()の戻り値として返却

## 処理フロー

### 処理シーケンス

```
1. StatsPrinter.print(type, object, baseContext) 呼び出し
   └─ _inPrintフラグを設定し、_print()を呼び出す
2. printフックで直接変換を試みる
   └─ 成功した場合はその結果を使用
3. 直接変換できない場合
   a. 配列: 各アイテムにprint再帰呼び出し → printItemsフックで結合
   b. オブジェクト: 各プロパティにprint再帰呼び出し → printElementsフックで結合
4. resultフックでウォーターフォール処理
   └─ 最終的な文字列を返却
5. _inPrintフラグ解除時にキャッシュクリア
```

### フローチャート

```mermaid
flowchart TD
    A[StatsPrinter.print呼び出し] --> B[printフック実行]
    B --> C{直接変換成功?}
    C -->|Yes| D[printResult確定]
    C -->|No| E{データ型判定}
    E -->|配列| F[各アイテムにprint再帰呼び出し]
    F --> G[printItemsフックで結合]
    E -->|オブジェクト| H[各プロパティにprint再帰呼び出し]
    H --> I[sortElementsフック]
    I --> J[printElementsフックで結合]
    G --> K[resultフックでウォーターフォール処理]
    J --> K
    D --> K
    K --> L[文字列返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-55-01 | 階層的フック解決 | "compilation.assets[].asset"のように型パスを分解し、各レベルでフックを探索する | StatsPrinter._getAllLevelHooks |
| BR-55-02 | キャッシュクリア | print呼び出し完了後にlevelHookCacheをクリアする | _inPrintフラグがfalseになる時 |
| BR-55-03 | undefinedフィルタ | オブジェクトのプロパティがundefinedの場合はスキップする | _print内オブジェクト処理 |
| BR-55-04 | 改行結合 | printItems/printElementsフックが未定義の場合、結果をBooleanフィルタして改行で結合する | デフォルト動作 |
| BR-55-05 | モジュール名短縮 | 80文字超のモジュール識別子は短縮して"...(truncated)"を付与する | DefaultStatsPrinterPlugin |
| BR-55-06 | データURI短縮 | data:URLは先頭16文字+内容で短縮表示する | DefaultStatsPrinterPlugin |

### 計算ロジック

フック解決: StatsFactoryと同様に、型パスを分解して各レベルでHookMapを探索する。フォーマッタ関数（formatSize, formatTime等）はbaseContextを通じて提供される。

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

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

| 操作 | 対象テーブル | 操作種別 | 概要 |
|-----|-------------|---------|------|
| - | - | - | 本機能はデータベースを使用しない |

### テーブル別操作詳細

該当なし（インメモリ処理のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | - | 本機能自体はエラーをスローしない | フック内例外は上位で処理 |

### リトライ仕様

該当なし。

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

該当なし（同期的なインメモリ処理）

## パフォーマンス要件

- 統計出力の整形処理は通常軽量であるが、大量のモジュール・チャンクがある場合は出力文字列が大きくなる
- modulesSpace, assetsSpace等のSpace系オプションで表示件数を制限可能

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

特になし（出力内容の制御はstatsオプションで行う）。

## 備考

- StatsFactory(No.54) → StatsPrinter(No.55)の2段階アーキテクチャ
- DefaultStatsPrinterPluginは色付け、サイズフォーマット、時間フォーマット等の豊富なフォーマッタを提供する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | StatsPrinter.js | `lib/stats/StatsPrinter.js` | StatsPrintHooksの型定義とHookMapの構造を理解する |

**読解のコツ**: StatsPrinterのフック構造はStatsFactoryと類似しているが、print/printElements/printItemsの3層構造で文字列化を行う点が異なる。

- **24-27行目**: PrintedElement型 - { element, content }の構造
- **30-45行目**: KnownStatsPrinterContextの型定義
- **47行目**: ColorFunction型 - 色付け関数
- **60-70行目**: KnownStatsPrinterFormattersの型定義 - formatFilename, formatSize, formatTime等
- **77-85行目**: StatsPrintHooksの型定義 - sortElements, printElements, sortItems, getItemName, printItems, print, result
- **87-108行目**: StatsPrinterコンストラクタ - HookMapの初期化

#### Step 2: プリンタの実行フローを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | StatsPrinter.js | `lib/stats/StatsPrinter.js` | print()メソッドと_print()メソッドの全体フロー |

**主要処理フロー**:
1. **184-195行目**: `print()`メソッド - _inPrintフラグ管理とキャッシュクリア
2. **204-210行目**: `_print()`メソッド - コンテキスト構築
3. **213-215行目**: printフックで直接変換を試みる
4. **217-254行目**: 配列の場合 - sortItems→各アイテムにprint再帰→printItems
5. **256-286行目**: オブジェクトの場合 - sortElements→各プロパティにprint再帰→printElements
6. **290-296行目**: resultフックでウォーターフォール処理

#### Step 3: DefaultStatsPrinterPluginのフォーマットロジック

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | DefaultStatsPrinterPlugin.js | `lib/stats/DefaultStatsPrinterPlugin.js` | 各統計要素のフォーマット定義 |

**主要処理フロー**:
- **36行目**: DATA_URI_CONTENT_LENGTH = 16
- **37行目**: MAX_MODULE_IDENTIFIER_LENGTH = 80
- **44行目**: plural関数 - 単数/複数形の切り替え
- **51-58行目**: printSizes関数 - サイズ表示のフォーマット
- **64-75行目**: getResourceName関数 - data:URLの短縮表示
- **81-98行目**: getModuleName関数 - モジュール名の短縮（80文字超の場合）

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

```
Stats.toString(options)
    │
    └─ StatsPrinter.print("compilation", statsCompilation, context)
           │
           ├─ hooks.print("compilation") ──▶ DefaultStatsPrinterPlugin
           │
           ├─ [オブジェクトの場合]
           │      ├─ hooks.sortElements("compilation")
           │      ├─ 各プロパティにprint再帰呼び出し
           │      │      ├─ print("compilation.hash", ...)
           │      │      ├─ print("compilation.assets", ...)  ──▶ [配列処理]
           │      │      ├─ print("compilation.modules", ...) ──▶ [配列処理]
           │      │      └─ print("compilation.errors", ...)  ──▶ [配列処理]
           │      └─ hooks.printElements("compilation")
           │
           └─ hooks.result("compilation")
                  └─ 最終文字列返却
```

### データフロー図

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

StatsCompilation ──────────▶ StatsPrinter.print() ──────────▶ string
  ├─ hash                      ├─ printフック（直接変換）
  ├─ assets[]                  ├─ printElements（オブジェクト展開）
  ├─ modules[]                 ├─ printItems（配列展開）
  ├─ errors[]                  └─ result（最終整形）
  └─ warnings[]

StatsPrinterContext            フォーマッタ関数
  ├─ formatSize ──────────▶ "1.2 KiB"
  ├─ formatTime ──────────▶ "120 ms"
  ├─ bold ────────────────▶ "\x1b[1m...\x1b[22m"
  └─ red ─────────────────▶ "\x1b[31m...\x1b[39m"
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| StatsPrinter.js | `lib/stats/StatsPrinter.js` | ソース | 統計プリンタ本体（HookMapベースのprint処理） |
| DefaultStatsPrinterPlugin.js | `lib/stats/DefaultStatsPrinterPlugin.js` | ソース | デフォルト統計フォーマットプラグイン |
| StatsFactory.js | `lib/stats/StatsFactory.js` | ソース | 統計ファクトリ（プリンタの入力を生成） |
