# 機能設計書 35-インデント制御（indent、dedent、align）

## 概要

本ドキュメントは、PrettierのDocument Builder APIにおけるインデント制御機能について記述する。この機能は、フォーマット出力におけるインデントレベルの増減と位置揃えを制御するDocビルダーを提供する。

### 本機能の処理概要

インデント制御は、Prettierの中間表現（Doc）において、インデントレベルの増減と位置揃えを制御する機能である。`indent`、`dedent`、`dedentToRoot`、`align`、`markAsRoot`、`addAlignmentToDoc`の各関数を提供し、ネストされたコード構造のフォーマットを実現する。

**業務上の目的・背景**：プログラミング言語のフォーマットでは、ブロック、関数、オブジェクトなどのネスト構造に応じて適切なインデントを適用する必要がある。インデント制御機能により、コードの論理構造を視覚的に表現し、可読性の高いフォーマット出力を実現する。また、位置揃え（align）により、特定の位置からの相対的なインデントも可能。

**機能の利用シーン**：
- 関数本体やブロック文の内部をインデントする場合
- オブジェクトリテラルや配列のネスト構造をフォーマットする場合
- メソッドチェーンで位置を揃える場合
- テンプレートリテラル内でインデントをリセットする場合

**主要な処理内容**：
1. indent: 内容のインデントレベルを1段階増加
2. dedent: 内容のインデントレベルを1段階減少
3. dedentToRoot: インデントをルートレベル（0）にリセット
4. align: 指定した数値/文字列分の位置揃えを適用
5. markAsRoot: 現在位置を新しいルートとしてマーク
6. addAlignmentToDoc: サイズとタブ幅を考慮したインデント追加

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

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

## 関連画面

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

## 機能種別

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

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| contents | Doc | Yes | インデントを適用する内容 | 有効なDocであること |
| alignType | number \| string \| AlignTypeRoot | Yes（align） | 位置揃えの幅または文字列 | 数値、文字列、またはAlignTypeRoot |
| size | number | Yes（addAlignmentToDoc） | インデントサイズ | 0以上の数値 |
| tabWidth | number | Yes（addAlignmentToDoc） | タブ幅 | 1以上の数値 |

### 入力データソース

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

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| indent(contents) | Indent | インデント増加Doc |
| dedent(contents) | Align | インデント減少Doc（align(-1)） |
| dedentToRoot(contents) | Align | ルートへのインデントリセットDoc |
| align(n, contents) | Align | 位置揃えDoc |
| markAsRoot(contents) | Align | ルートマーキングDoc |
| addAlignmentToDoc(doc, size, tabWidth) | Doc | サイズ指定インデントDoc |

### 出力先

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

## 処理フロー

### 処理シーケンス

```
1. プリンター関数でDoc構築時にindent/dedent/align等を使用
2. printDocToString関数でDoc処理時にインデント制御を評価
3. DOC_TYPE_INDENTの場合
   └─ makeIndent関数で現在のインデントを1段階増加
4. DOC_TYPE_ALIGNの場合
   └─ makeAlign関数で指定された幅の位置揃えを適用
5. 改行出力時にインデント文字列を適用
```

### フローチャート

```mermaid
flowchart TD
    A[Doc処理開始] --> B{Docタイプは?}
    B -->|DOC_TYPE_INDENT| C[makeIndent実行]
    B -->|DOC_TYPE_ALIGN| D[makeAlign実行]
    C --> E[新しいインデント生成]
    D --> F{n値の型は?}
    F -->|number > 0| G[スペース追加]
    F -->|number < 0| H[デデント処理]
    F -->|number === -Infinity| I[ルートリセット]
    F -->|string| J[文字列追加]
    F -->|{type: root}| K[ルートマーキング]
    E --> L[内容Doc処理]
    G --> L
    H --> L
    I --> L
    J --> L
    K --> L
    L --> M[改行時にインデント適用]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-35-01 | indent動作 | インデントレベルを1段階増加 | indent関数使用時 |
| BR-35-02 | dedent動作 | インデントレベルを1段階減少（align(-1)として実装） | dedent関数使用時 |
| BR-35-03 | dedentToRoot動作 | インデントをルートレベル（0）にリセット（align(-Infinity)として実装） | dedentToRoot関数使用時 |
| BR-35-04 | align正数動作 | 指定数のスペースを追加 | align(n)でn>0の場合 |
| BR-35-05 | align文字列動作 | 指定文字列をインデントに追加 | align(str)で文字列指定の場合 |
| BR-35-06 | markAsRoot動作 | 現在位置を新しいルートとしてマーク | markAsRoot関数使用時 |
| BR-35-07 | addAlignmentToDoc動作 | タブ幅を考慮してインデントを追加 | addAlignmentToDoc関数使用時 |

### 計算ロジック

indent Doc生成:
```javascript
function indent(contents) {
  assertDoc(contents);
  return { type: DOC_TYPE_INDENT, contents };
}
```

align Doc生成:
```javascript
function align(alignType, contents) {
  assertAlignType(alignType);
  assertDoc(contents);
  return { type: DOC_TYPE_ALIGN, contents, n: alignType };
}
```

addAlignmentToDoc:
```javascript
function addAlignmentToDoc(doc, size, tabWidth) {
  let aligned = doc;
  if (size > 0) {
    // タブ分のindentを追加
    for (let level = 0; level < Math.floor(size / tabWidth); ++level) {
      aligned = indent(aligned);
    }
    // 残りのスペースをalignで追加
    aligned = align(size % tabWidth, aligned);
    // ルートからの絶対位置にリセット
    aligned = align(Number.NEGATIVE_INFINITY, aligned);
  }
  return aligned;
}
```

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | AssertionError | 不正なcontentsが渡された場合 | 有効なDocを渡す |
| - | AssertionError | 不正なalignTypeが渡された場合 | 有効なalignType（数値/文字列/AlignTypeRoot）を渡す |

### リトライ仕様

リトライは行わない。

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

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

## パフォーマンス要件

- Doc構築は軽量なオブジェクト生成のみ
- インデント計算はprintDocToString実行時に一度のみ

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

特になし

## 備考

- dedentはalign(-1)、dedentToRootはalign(-Infinity)として内部実装
- markAsRootはテンプレートリテラル内のフォーマットで使用

---

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

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

### 推奨読解順序

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

インデント制御Docの型定義と構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | indent.js | `src/document/builders/indent.js` | Indent型定義とindent関数 |
| 1-2 | align.js | `src/document/builders/align.js` | Align型定義、align、dedent、dedentToRoot、markAsRoot関数 |

**読解のコツ**:
- `indent`は`{ type: DOC_TYPE_INDENT, contents }`を返す
- `align`は`{ type: DOC_TYPE_ALIGN, contents, n }`を返す
- `dedent`/`dedentToRoot`/`markAsRoot`は`align`のラッパー

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | indent.js | `src/document/builders/indent.js` | indent関数の実装 |
| 2-2 | align.js | `src/document/builders/align.js` | align、dedent、dedentToRoot、markAsRoot、addAlignmentToDoc関数 |

**主要処理フロー**:
1. **indent.js 13-17行目**: indent関数 - contentsを検証してIndent Docを生成
2. **align.js 24-29行目**: align関数 - alignTypeとcontentsを検証してAlign Docを生成
3. **align.js 35-37行目**: dedentToRoot関数 - align(Number.NEGATIVE_INFINITY)として実装
4. **align.js 43-45行目**: markAsRoot関数 - align({ type: "root" })として実装
5. **align.js 51-53行目**: dedent関数 - align(-1)として実装
6. **align.js 61-77行目**: addAlignmentToDoc関数 - タブ幅を考慮したインデント追加

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | printer.js | `src/document/printer/printer.js` | DOC_TYPE_INDENT/DOC_TYPE_ALIGN処理 |
| 3-2 | indent.js | `src/document/printer/indent.js` | makeIndent、makeAlign関数 |

**主要処理フロー**:
- **printer.js 225-231行目**: DOC_TYPE_INDENTの処理 - makeIndentでインデント増加
- **printer.js 233-239行目**: DOC_TYPE_ALIGNの処理 - makeAlignで位置揃え

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

```
builders.indent (indent.js:13)
    │
    └─ assertDoc → Indent Doc生成
           │
           └─ printDocToString (printer.js:179)
                  │
                  └─ DOC_TYPE_INDENT処理 (printer.js:225)
                         │
                         └─ makeIndent (indent.js) → 新インデント生成

builders.align / dedent / dedentToRoot / markAsRoot (align.js)
    │
    └─ assertAlignType → assertDoc → Align Doc生成
           │
           └─ printDocToString (printer.js:179)
                  │
                  └─ DOC_TYPE_ALIGN処理 (printer.js:233)
                         │
                         └─ makeAlign (indent.js) → 位置揃え適用

builders.addAlignmentToDoc (align.js:61)
    │
    ├─ assertDoc
    │
    └─ タブ幅計算
           │
           ├─ indent × (size / tabWidth)回
           │
           ├─ align(size % tabWidth)
           │
           └─ align(Number.NEGATIVE_INFINITY)
```

### データフロー図

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

contents            indent / align                    Indent/Align Doc
alignType ─────────▶ Doc生成 ────────────────────────▶
                          │
                          ▼
                   printDocToString
                          │
                ┌─────────┴─────────┐
                │                   │
         [DOC_TYPE_INDENT]   [DOC_TYPE_ALIGN]
                │                   │
                ▼                   ▼
           makeIndent           makeAlign
                │                   │
                └─────────┬─────────┘
                          │
                          ▼
                   改行時にインデント適用
                          │
                          ▼
                   フォーマット文字列
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| indent.js | `src/document/builders/indent.js` | ソース | indent関数の定義 |
| align.js | `src/document/builders/align.js` | ソース | align、dedent、dedentToRoot、markAsRoot、addAlignmentToDoc関数の定義 |
| types.js | `src/document/builders/types.js` | ソース | DOC_TYPE_INDENT、DOC_TYPE_ALIGN定数 |
| index.js | `src/document/builders/index.js` | ソース | ビルダーのエクスポート |
| public.js | `src/document/public.js` | ソース | 公開APIのエクスポート |
| printer.js | `src/document/printer/printer.js` | ソース | Doc処理とフォーマット出力 |
| indent.js | `src/document/printer/indent.js` | ソース | makeIndent、makeAlign関数の実装 |
| assert-doc.js | `src/document/utilities/assert-doc.js` | ソース | Docアサーション関数 |
