# 機能設計書 39-Docユーティリティ

## 概要

本ドキュメントは、PrettierのDocument Builder APIにおけるDocユーティリティ機能について記述する。この機能は、Doc操作用のユーティリティ関数群（willBreak、mapDoc、traverseDoc等）を提供する。

### 本機能の処理概要

Docユーティリティは、Prettierの中間表現（Doc）を操作・分析するためのユーティリティ関数群である。Doc構造の走査、変換、分析を行う各種関数を提供し、プリンター実装やデバッグ時に活用される。

**業務上の目的・背景**：Prettierのプリンターを実装する際、生成したDocを分析したり変換したりする必要がある。例えば、Docが改行を含むかどうかの判定、Doc構造の変換、特定パターンの検索などが必要となる。Docユーティリティはこれらの共通処理を提供し、プリンター実装の効率化と品質向上に貢献する。

**機能の利用シーン**：
- 生成したDocが改行を含むか判定する場合（willBreak）
- Doc構造を変換する場合（mapDoc）
- Doc構造を走査する場合（traverseDoc）
- 特定のパターンをDoc内から検索する場合（findInDoc）
- 行を削除する場合（removeLines）
- 末尾のhardlineを削除する場合（stripTrailingHardline）
- 改行を別のDocに置換する場合（replaceEndOfLine）

**主要な処理内容**：
1. willBreak: Docが改行を強制するか判定
2. mapDoc: Doc構造を変換
3. traverseDoc: Doc構造を走査
4. findInDoc: Doc内から特定パターンを検索
5. removeLines: 行を削除
6. stripTrailingHardline: 末尾hardlineを削除
7. replaceEndOfLine: 改行を置換
8. canBreak: 改行の可能性があるか判定

**関連システム・外部連携**：Document Printer、各言語プリンター

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

## 関連画面

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

## 機能種別

Document Builder API / ユーティリティ

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| doc | Doc | Yes | 操作対象のDoc | 有効なDocであること |
| cb | function | Yes（mapDoc） | 変換関数 | 関数であること |
| fn | function | Yes（findInDoc） | 検索関数 | 関数であること |
| onEnter | function | No（traverseDoc） | 進入時コールバック | 関数であること |
| onExit | function | No（traverseDoc） | 退出時コールバック | 関数であること |
| shouldTraverseConditionalGroups | boolean | No（traverseDoc） | conditionalGroupsを走査するか | booleanであること |
| defaultValue | any | No（findInDoc） | 見つからない場合のデフォルト値 | 任意 |
| replacement | Doc | No（replaceEndOfLine） | 置換するDoc（デフォルト: literalline） | 有効なDocであること |

### 入力データソース

- プリンター関数内でDoc操作時に使用
- utils.willBreakなどとしてインポート

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| willBreak(doc) | boolean | Docが改行を強制するか |
| mapDoc(doc, cb) | Doc | 変換後のDoc |
| traverseDoc(doc, ...) | void | 走査（副作用のみ） |
| findInDoc(doc, fn, defaultValue) | any | 検索結果またはdefaultValue |
| removeLines(doc) | Doc | 行を削除したDoc |
| stripTrailingHardline(doc) | Doc | 末尾hardlineを削除したDoc |
| replaceEndOfLine(doc, replacement) | Doc | 改行を置換したDoc |
| canBreak(doc) | boolean | 改行の可能性があるか |

### 出力先

プリンター関数内で使用、または分析結果として返却

## 処理フロー

### 処理シーケンス

```
1. traverseDoc: Doc構造をスタックベースで走査
   └─ onEnter/onExitコールバックを適切なタイミングで呼び出し
2. mapDoc: Doc構造を再帰的に変換
   └─ キャッシュを使用して同一サブツリーの再処理を回避
3. findInDoc: traverseDocを使用して検索
   └─ 見つかり次第早期リターン
4. willBreak: findInDocを使用して改行強制を判定
   └─ group.break=true、line.hard=true、breakParentを検索
5. removeLines: mapDocを使用して行を削除
   └─ softline→""、line→" "、ifBreak→flatContents
6. stripTrailingHardline: 末尾のhardlineを再帰的に削除
7. replaceEndOfLine: 文字列内の改行をDocに置換
8. canBreak: findInDocを使用して行の存在を判定
```

### フローチャート

```mermaid
flowchart TD
    A[ユーティリティ関数呼び出し] --> B{関数は?}
    B -->|traverseDoc| C[スタックベース走査]
    B -->|mapDoc| D[再帰的変換]
    B -->|findInDoc| E[traverseDoc使用検索]
    B -->|willBreak| F[findInDoc使用判定]
    B -->|removeLines| G[mapDoc使用行削除]
    B -->|stripTrailingHardline| H[末尾hardline削除]
    B -->|replaceEndOfLine| I[改行置換]
    B -->|canBreak| J[findInDoc使用判定]
    C --> K[各ノードでonEnter/onExit呼び出し]
    D --> L[キャッシュ確認後変換]
    E --> M[条件一致で早期リターン]
    F --> N[break/hard/breakParent検索]
    G --> O[line→space、softline→empty]
    H --> P[末尾から再帰的に削除]
    I --> Q[文字列分割しjoinで結合]
    J --> R[DOC_TYPE_LINE存在確認]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-01 | traverseDocスタック処理 | 再帰ではなくスタックベースで走査（パフォーマンス向上） | traverseDoc使用時 |
| BR-39-02 | mapDocキャッシュ | 同一サブツリーの変換結果をキャッシュ | mapDoc使用時 |
| BR-39-03 | findInDoc早期リターン | 条件一致時点で走査を停止 | findInDoc使用時 |
| BR-39-04 | willBreak判定条件 | group.break=true、line.hard=true、breakParentで true | willBreak使用時 |
| BR-39-05 | removeLines変換 | softline→""、line→" "、ifBreak→flatContents | removeLines使用時 |
| BR-39-06 | onEnter戻り値 | falseを返すと子ノードの走査をスキップ | traverseDoc使用時 |

### 計算ロジック

willBreak判定:
```javascript
function willBreakFn(doc) {
  if (doc.type === DOC_TYPE_GROUP && doc.break) {
    return true;
  }
  if (doc.type === DOC_TYPE_LINE && doc.hard) {
    return true;
  }
  if (doc.type === DOC_TYPE_BREAK_PARENT) {
    return true;
  }
}

function willBreak(doc) {
  return findInDoc(doc, willBreakFn, false);
}
```

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

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

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

## エラー処理

### エラーケース一覧

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

### リトライ仕様

リトライは行わない。

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

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

## パフォーマンス要件

- traverseDocはスタックベースで再帰オーバーフローを回避
- mapDocはMapでキャッシュし同一サブツリーの再処理を回避
- findInDocは早期リターンで不要な走査を回避

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

特になし

## 備考

- utilsオブジェクトとしてエクスポートされる
- プラグイン開発時に活用される

---

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

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

### 推奨読解順序

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

Docユーティリティの型定義と構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.js | `src/document/utilities/index.js` | ユーティリティ関数群の定義 |
| 1-2 | traverse-doc.js | `src/document/utilities/traverse-doc.js` | traverseDoc関数の実装 |

**読解のコツ**:
- traverseDocはスタックベースで実装されている
- mapDocはMapでキャッシュを使用
- findInDocはtraverseDocを使用

#### Step 2: 基本関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | traverse-doc.js | `src/document/utilities/traverse-doc.js` | traverseDoc関数の実装 |

**主要処理フロー**:
1. **36-111行目**: traverseDoc関数
2. **37行目**: docsStackにdocをpush
3. **39-110行目**: whileループでスタックを処理
4. **42-44行目**: onExitマーカー処理
5. **47-49行目**: onExit用のスタック操作
6. **57-59行目**: onEnterコールバック呼び出し
7. **66-109行目**: Docタイプに応じた子ノードのpush

#### Step 3: 変換・検索関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | index.js | `src/document/utilities/index.js` | mapDoc、findInDoc、willBreak等の実装 |

**主要処理フロー**:
- **29-99行目**: mapDoc関数 - Doc構造を変換
- **101-117行目**: findInDoc関数 - Doc内から検索
- **119-133行目**: willBreak関数 - 改行強制判定
- **180-198行目**: removeLines関数 - 行を削除
- **262-265行目**: stripTrailingHardline関数 - 末尾hardline削除
- **360-366行目**: replaceEndOfLine関数 - 改行置換
- **368-376行目**: canBreak関数 - 改行可能性判定

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

```
utils.traverseDoc (traverse-doc.js:36)
    │
    └─ スタックベース走査
           │
           ├─ onEnter呼び出し
           │
           └─ onExit呼び出し

utils.mapDoc (index.js:29)
    │
    ├─ キャッシュ確認
    │
    └─ 再帰的変換
           │
           └─ cbコールバック呼び出し

utils.findInDoc (index.js:101)
    │
    └─ traverseDoc使用
           │
           └─ fn条件一致で早期リターン

utils.willBreak (index.js:131)
    │
    └─ findInDoc使用
           │
           └─ willBreakFn判定

utils.removeLines (index.js:196)
    │
    └─ mapDoc使用
           │
           └─ removeLinesFn変換

utils.stripTrailingHardline (index.js:262)
    │
    └─ cleanDoc + stripTrailingHardlineFromDoc

utils.replaceEndOfLine (index.js:360)
    │
    └─ mapDoc使用
           │
           └─ 文字列をjoinで結合

utils.canBreak (index.js:374)
    │
    └─ findInDoc使用
           │
           └─ canBreakFn判定
```

### データフロー図

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

Doc                   traverseDoc                       void (副作用)
onEnter ─────────────▶ スタック走査 ─────────────────▶
onExit                     │
                           ▼
                    各ノードでコールバック


Doc                   mapDoc                            変換後Doc
cb ──────────────────▶ 再帰的変換 ─────────────────────▶
                           │
                           ▼
                    キャッシュ確認 + cb呼び出し


Doc                   findInDoc                         検索結果
fn ──────────────────▶ traverseDoc使用 ─────────────────▶
defaultValue               │
                           ▼
                    条件一致で早期リターン


Doc                   willBreak                         boolean
 ──────────────────▶ findInDoc使用 ─────────────────────▶
                           │
                           ▼
                    break/hard/breakParent検索
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.js | `src/document/utilities/index.js` | ソース | ユーティリティ関数群の定義 |
| traverse-doc.js | `src/document/utilities/traverse-doc.js` | ソース | traverseDoc関数 |
| get-doc-type.js | `src/document/utilities/get-doc-type.js` | ソース | Docタイプ判定 |
| invalid-doc-error.js | `src/document/utilities/invalid-doc-error.js` | ソース | InvalidDocError定義 |
| assert-doc.js | `src/document/utilities/assert-doc.js` | ソース | Docアサーション |
| public.js | `src/document/public.js` | ソース | 公開APIのエクスポート |
