# 機能設計書 36-グループ化（group、conditionalGroup）

## 概要

本ドキュメントは、PrettierのDocument Builder APIにおけるグループ化機能について記述する。この機能は、出力を可能な限り1行に収めるよう試み、収まらない場合は複数行に分割するDocビルダーを提供する。

### 本機能の処理概要

グループ化は、Prettierの中間表現（Doc）において、出力の折り返し制御を行う最も重要な機能である。`group`関数は内容を可能な限り1行に収め（FLATモード）、収まらない場合は複数行に分割（BREAKモード）する。`conditionalGroup`関数は複数の代替表現を提供し、最初に収まるものを選択する。

**業務上の目的・背景**：コードフォーマットでは、可読性を維持しながらprintWidth内に収めることが重要である。短いコードは1行で表示し、長いコードは適切に折り返すことで、一貫性のある読みやすいフォーマットを実現する。グループ化機能はこの動的な判断を自動化し、開発者が明示的に改行位置を指定することなく最適なフォーマットを提供する。

**機能の利用シーン**：
- 関数呼び出しの引数リストを1行または複数行で出力する場合
- 配列やオブジェクトリテラルをコンパクトまたは展開形式で出力する場合
- 三項演算子を1行または複数行で出力する場合
- 複数の代替フォーマットから最適なものを選択する場合

**主要な処理内容**：
1. group: 内容をFLATモードで試行し、収まらなければBREAKモードに切り替え
2. conditionalGroup: 複数の状態から最初に収まるものを選択
3. shouldBreakオプション: グループを強制的にBREAKモードにする
4. idオプション: グループにIDを付与し、ifBreakから参照可能にする

**関連システム・外部連携**：Document Printer（printDocToString）、fits関数

**権限による制御**：特になし

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 14 | Usage - Plugins | 主画面 | プラグイン作成時のグループ化機能を説明 |
| 26 | Misc - Technical Details | 参照画面 | グループ化の技術的詳細を説明 |

## 機能種別

Document Builder API / フォーマット制御

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| contents | Doc | Yes | グループ化する内容 | 有効なDocであること |
| options | GroupOptions | No | グループオプション | オブジェクトであること |
| options.id | symbol | No | グループID（ifBreakから参照用） | symbolであること |
| options.shouldBreak | boolean | No | 強制BREAKモード | booleanであること |
| options.expandedStates | Doc[] | No | 代替状態の配列（conditionalGroup用） | Doc配列であること |
| states | Doc[] | Yes（conditionalGroup） | 代替状態の配列 | Doc配列であること |

### 入力データソース

- プリンター関数内でDoc構築時に使用
- builders.groupなどとしてインポート

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| group(contents, options) | Group | グループDoc |
| conditionalGroup(states, options) | Group | 条件付きグループDoc |

### 出力先

Doc構造としてDocument Printerに渡される

## 処理フロー

### 処理シーケンス

```
1. プリンター関数でDoc構築時にgroup/conditionalGroupを使用
2. printDocToString関数でDoc処理時にグループを評価
3. DOC_TYPE_GROUPの処理
   ├─ shouldBreak=trueの場合 → BREAKモード
   └─ shouldBreak=falseの場合
       └─ fits関数で1行に収まるか判定
           ├─ 収まる → FLATモード
           └─ 収まらない
               ├─ expandedStatesなし → BREAKモード
               └─ expandedStatesあり → 代替状態を順に試行
4. 選択されたモードで内容を出力
5. グループIDがあればモードをgroupModeMapに記録
```

### フローチャート

```mermaid
flowchart TD
    A[DOC_TYPE_GROUP処理] --> B{現在FLATモード?}
    B -->|Yes + !shouldRemeasure| C{shouldBreak?}
    B -->|No または shouldRemeasure| D[グループ評価開始]
    C -->|Yes| E[BREAKモード確定]
    C -->|No| F[FLATモード継続]
    D --> G{shouldBreak?}
    G -->|Yes| E
    G -->|No| H[fits関数で判定]
    H --> I{1行に収まる?}
    I -->|Yes| J[FLATモードで出力]
    I -->|No| K{expandedStatesあり?}
    K -->|No| L[BREAKモードで出力]
    K -->|Yes| M[代替状態を順に試行]
    M --> N{収まる状態あり?}
    N -->|Yes| O[その状態で出力]
    N -->|No| P[最後の状態でBREAK出力]
    E --> Q[内容処理]
    F --> Q
    J --> Q
    L --> Q
    O --> Q
    P --> Q
    Q --> R{idあり?}
    R -->|Yes| S[groupModeMapに記録]
    R -->|No| T[次のDoc処理]
    S --> T
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-36-01 | FLATモード優先 | 1行に収まる場合はFLATモードを使用 | fits関数がtrueを返す場合 |
| BR-36-02 | shouldBreak強制 | shouldBreak=trueの場合は強制的にBREAKモード | オプション指定時 |
| BR-36-03 | expandedStates探索 | 代替状態を前から順に試行し、最初に収まるものを使用 | conditionalGroup使用時 |
| BR-36-04 | 最終状態フォールバック | どの状態も収まらない場合は最後の状態をBREAKモードで使用 | すべての状態が収まらない場合 |
| BR-36-05 | グループID記録 | idオプション指定時はモードをgroupModeMapに記録 | id指定時 |
| BR-36-06 | breakParent伝播 | 子グループがBREAKの場合、親グループにも伝播可能 | propagateBreaks処理時 |

### 計算ロジック

group Doc生成:
```javascript
function group(contents, options = {}) {
  assertDoc(contents);
  assertDocArray(options.expandedStates, /* optional */ true);

  return {
    type: DOC_TYPE_GROUP,
    id: options.id,
    contents,
    break: Boolean(options.shouldBreak),
    expandedStates: options.expandedStates,
  };
}
```

conditionalGroup Doc生成:
```javascript
function conditionalGroup(states, options) {
  return group(states[0], { ...options, expandedStates: states });
}
```

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

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

本機能はデータベースを使用しない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | AssertionError | 不正なcontentsが渡された場合 | 有効なDocを渡す |
| - | AssertionError | 不正なexpandedStatesが渡された場合 | 有効なDoc配列を渡す |

### リトライ仕様

リトライは行わない。

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

本機能はトランザクション管理を必要としない。

## パフォーマンス要件

- fits関数は残り幅を超えた時点で早期リターン
- propagateBreaksでbreakParent伝播を事前処理
- groupModeMapで既に評価済みのグループモードをキャッシュ

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

特になし

## 備考

- conditionalGroupはgroupのshouldBreakオプションとexpandedStatesを使用したラッパー
- fits関数はスタックベースの再帰的処理で行幅を計算

---

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

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

### 推奨読解順序

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

グループDocの型定義と構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | group.js | `src/document/builders/group.js` | Group型定義、group関数、conditionalGroup関数 |

**読解のコツ**:
- `Group`型は`type`、`id`、`contents`、`break`、`expandedStates`プロパティを持つ
- `conditionalGroup`は`group`のラッパーで、`expandedStates`を設定

#### Step 2: ビルダー関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | group.js | `src/document/builders/group.js` | group関数、conditionalGroup関数の実装 |

**主要処理フロー**:
1. **22-33行目**: group関数 - contentsを検証してGroup Docを生成
2. **40-42行目**: conditionalGroup関数 - states[0]をcontentsとし、expandedStatesを設定

#### Step 3: プリンターでの処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | printer.js | `src/document/printer/printer.js` | DOC_TYPE_GROUP処理、fits関数 |

**主要処理フロー**:
- **53-169行目**: fits関数 - 残り幅内に収まるか判定
- **122-134行目**: fits関数内のグループ処理 - expandedStatesの場合は最後の状態を使用
- **245-322行目**: printDocToString内のDOC_TYPE_GROUP処理
- **248-255行目**: FLATモードでshouldRemeasure不要の場合の処理
- **257-274行目**: fits関数でFLATモードを試行
- **276-311行目**: expandedStates処理 - 代替状態を順に試行

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

```
builders.group (group.js:22)
    │
    └─ assertDoc / assertDocArray → Group Doc生成
           │
           └─ printDocToString (printer.js:179)
                  │
                  └─ DOC_TYPE_GROUP処理 (printer.js:245)
                         │
                         ├─ [FLATモード + !shouldRemeasure]
                         │      │
                         │      └─ shouldBreak確認 → FLATまたはBREAK
                         │
                         └─ [BREAKモードまたはshouldRemeasure]
                                │
                                └─ fits関数 (printer.js:53)
                                       │
                                       ├─ [収まる] → FLATモード
                                       │
                                       └─ [収まらない]
                                              │
                                              ├─ [expandedStatesなし] → BREAKモード
                                              │
                                              └─ [expandedStatesあり]
                                                     │
                                                     └─ 代替状態を順に試行
                                                            │
                                                            └─ 最初に収まる状態を使用

builders.conditionalGroup (group.js:40)
    │
    └─ group(states[0], { ...options, expandedStates: states })
```

### データフロー図

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

contents             group / conditionalGroup           Group Doc
options ────────────▶ Doc生成 ──────────────────────▶
                            │
                            ▼
                     printDocToString
                            │
                            ▼
                     DOC_TYPE_GROUP処理
                            │
              ┌─────────────┴─────────────┐
              │                           │
         [shouldBreak]              [!shouldBreak]
              │                           │
              ▼                           ▼
         BREAKモード               fits関数で判定
                                          │
                                ┌─────────┴─────────┐
                                │                   │
                           [収まる]            [収まらない]
                                │                   │
                                ▼                   ▼
                           FLATモード    expandedStates処理
                                                    │
                                          ┌─────────┴─────────┐
                                          │                   │
                                     [なし]             [あり]
                                          │                   │
                                          ▼                   ▼
                                     BREAKモード       代替状態試行
                                                              │
                                                              ▼
                                                    最初に収まる状態
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| group.js | `src/document/builders/group.js` | ソース | group、conditionalGroup関数の定義 |
| types.js | `src/document/builders/types.js` | ソース | DOC_TYPE_GROUP定数 |
| index.js | `src/document/builders/index.js` | ソース | ビルダーのエクスポート |
| public.js | `src/document/public.js` | ソース | 公開APIのエクスポート |
| printer.js | `src/document/printer/printer.js` | ソース | DOC_TYPE_GROUP処理、fits関数 |
| index.js | `src/document/utilities/index.js` | ソース | propagateBreaks関数 |
| assert-doc.js | `src/document/utilities/assert-doc.js` | ソース | Docアサーション関数 |
