# 機能設計書 11-fmt

## 概要

本ドキュメントは、Zigコンパイラに組み込まれたコードフォーマッター機能「fmt」の設計仕様を記載する。`zig fmt`コマンドは、Zigソースコード（`.zig`ファイル）およびZON設定ファイル（`.zon`ファイル）を正規のフォーマットに自動整形する機能を提供する。

### 本機能の処理概要

**業務上の目的・背景**：ソフトウェア開発プロジェクトにおいて、コードスタイルの統一は可読性の向上、コードレビューの効率化、チーム間の協調作業の円滑化に不可欠である。手動でのフォーマット調整は非効率であり、開発者間でスタイルが異なるとコンフリクトや可読性低下の原因となる。本機能は、Zig言語公式の正規フォーマットを自動適用することで、これらの課題を解決し、開発生産性を向上させる。

**機能の利用シーン**：
- 開発者がコードを書いた後、コミット前にフォーマットを統一したい場合
- CI/CDパイプラインでコードスタイルの一貫性をチェックしたい場合（`--check`オプション）
- 複数のファイルやディレクトリに対して一括でフォーマットを適用したい場合
- IDEやエディタからの自動フォーマット連携時
- 標準入力からのコードをフォーマットして標準出力に出力したい場合

**主要な処理内容**：
1. コマンドライン引数の解析（オプション、入力ファイル/ディレクトリの特定）
2. 入力ソースコードの読み込み（ファイル、ディレクトリ再帰、または標準入力）
3. Zig AST（抽象構文木）への解析（`std.zig.Ast.parse`）
4. オプション指定時のAST検査（`--ast-check`による意味解析エラーの検出）
5. ASTからの正規フォーマットコード生成（`tree.render`/`tree.renderAlloc`）
6. 出力処理（ファイル上書き、標準出力、またはチェックモードでの差分報告）

**関連システム・外部連携**：
- 標準ライブラリ`std.zig.Ast`モジュール（構文解析・レンダリング）
- `std.zig.AstGen`モジュール（ZIR生成による意味解析チェック）
- `std.zig.ZonGen`モジュール（ZONファイルの意味解析チェック）
- ファイルシステムI/O（`std.Io`）

**権限による制御**：特に権限制御は実装されていない。ファイルシステムのアクセス権限に依存する。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 10 | フォーマット画面 | 主機能 | Zigソースコードを正規フォーマットに整形する処理 |

## 機能種別

コード変換処理 / データ検証（バリデーション）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| file/directory | []const u8 | 条件付き | フォーマット対象のファイルまたはディレクトリパス（複数指定可） | `--stdin`指定時は指定不可 |
| --stdin | フラグ | No | 標準入力からコードを読み込む | ファイル引数と併用不可 |
| --check | フラグ | No | フォーマット違反ファイルの一覧表示のみ（ファイル変更なし） | - |
| --ast-check | フラグ | No | 各ファイルに対してAST検査を実行 | - |
| --color | enum | No | カラー出力の制御（auto/off/on） | 指定値が有効な列挙値であること |
| --exclude | []const u8 | No | フォーマット対象から除外するファイル/ディレクトリ | - |
| --zon | フラグ | No | 全入力ファイルをZONとして扱う | - |
| -h, --help | フラグ | No | ヘルプメッセージを表示して終了 | - |

### 入力データソース

- ファイルシステム上のZigソースファイル（`.zig`）
- ファイルシステム上のZON設定ファイル（`.zon`）
- 標準入力（`--stdin`オプション使用時）

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| formatted_code | []const u8 | 正規フォーマットに整形されたソースコード |
| file_list | [][]const u8 | フォーマットされた（または違反している）ファイルパス一覧 |
| error_messages | ErrorBundle | 構文エラーまたは意味解析エラーメッセージ |

### 出力先

- ファイルシステム（元ファイルの上書き、アトミック書き込み）
- 標準出力（`--stdin`モード時、または`--check`モードでの違反ファイル一覧）
- 標準エラー出力（エラーメッセージ）

## 処理フロー

### 処理シーケンス

```
1. コマンドライン引数の解析
   └─ オプションフラグと入力ファイルリストを分離
2. 入力バリデーション
   └─ --stdinとファイル引数の排他チェック
   └─ 入力ファイル/ディレクトリの存在確認
3. 除外ファイルの登録
   └─ --excludeで指定されたパスをseenマップに追加
4. 入力ソースごとの処理ループ
   └─ ファイルの場合: fmtPathFile関数で処理
   └─ ディレクトリの場合: fmtPathDir関数で再帰処理
5. ファイル処理
   └─ ソースコード読み込み
   └─ AST解析（std.zig.Ast.parse）
   └─ 構文エラーチェック
   └─ --ast-check時: ZIR/ZOIR生成による意味解析
   └─ ASTから正規フォーマット生成（tree.render）
   └─ 差分確認
6. 出力処理
   └─ --check時: 差分があればファイルパスを標準出力に出力
   └─ 通常時: アトミックファイル書き込みで上書き
7. 終了処理
   └─ エラーがあればexit(1)、なければexit(0)
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B{--stdin?}
    B -->|Yes| C[標準入力から読み込み]
    B -->|No| D{入力ファイルあり?}
    D -->|No| E[エラー終了]
    D -->|Yes| F[除外ファイル登録]
    C --> G[AST解析]
    F --> H[ファイル/ディレクトリ処理ループ]
    H --> I{ディレクトリ?}
    I -->|Yes| J[再帰的にファイル探索]
    I -->|No| K[ファイル読み込み]
    J --> K
    K --> G
    G --> L{構文エラー?}
    L -->|Yes| M[エラー出力]
    L -->|No| N{--ast-check?}
    N -->|Yes| O[ZIR/ZOIR生成・検査]
    N -->|No| P[フォーマット生成]
    O --> Q{意味解析エラー?}
    Q -->|Yes| M
    Q -->|No| P
    P --> R{内容に変更あり?}
    R -->|No| S[次のファイルへ]
    R -->|Yes| T{--check?}
    T -->|Yes| U[ファイルパス出力]
    T -->|No| V[アトミック書き込み]
    U --> S
    V --> W[ファイルパス出力]
    W --> S
    M --> X[any_error = true]
    X --> S
    S --> Y{全ファイル処理完了?}
    Y -->|No| H
    Y -->|Yes| Z{any_error?}
    Z -->|Yes| AA[exit 1]
    Z -->|No| AB[exit 0]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ファイル拡張子判定 | `.zig`はZigコード、`.zon`はZONファイルとして処理 | `--zon`オプション未指定時 |
| BR-02 | ZON強制モード | 全入力ファイルをZONとして処理 | `--zon`オプション指定時 |
| BR-03 | 隠しファイル除外 | ドット（`.`）で始まるファイル/ディレクトリは自動的にスキップ | ディレクトリ再帰処理時 |
| BR-04 | 重複処理防止 | 同一inodeのファイルは一度のみ処理 | シンボリックリンク等による重複防止 |
| BR-05 | チェックモード終了コード | フォーマット違反ファイルがあればexit(1) | `--check`オプション指定時 |

### 計算ロジック

フォーマットの差分判定は、元のソースコードとフォーマット後のコードの単純なバイト比較（`mem.eql`）で行われる。

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 構文エラー | Zigソースコードに構文エラーがある場合 | エラー位置と内容を標準エラーに出力、any_error=true |
| - | 意味解析エラー | `--ast-check`時にZIR/ZOIR生成でエラー | エラー内容を標準エラーに出力、any_error=true |
| - | ファイルアクセスエラー | ファイルの読み取り/書き込み権限がない場合 | エラーログを出力、any_error=true |
| - | 引数エラー | 不正なオプション指定または必須引数不足 | 使用方法メッセージを表示してfatal終了 |

### リトライ仕様

ファイルI/Oエラー時のリトライは実装されていない。エラーが発生した場合は該当ファイルをスキップし、処理を継続する。

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

ファイル書き込みはアトミック操作（`createFileAtomic`）で行われる。一時ファイルに書き込み後、`replace`操作で元ファイルを置換することで、書き込み途中でのファイル破損を防止する。

## パフォーマンス要件

- 大量ファイルの処理に対応するため、seenマップによる重複処理防止を実装
- 出力バッファは入力ソースと同等の容量を事前確保し、再アロケーションを最小化
- ディレクトリ走査時は`.`で始まるエントリを早期スキップ

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

- ファイルシステムのパーミッションに従う
- 書き込み時は元ファイルのパーミッションを保持
- パストラバーサル攻撃への対策は呼び出し元に依存

## 備考

- `zig fmt`はGo言語の`gofmt`、Rust言語の`rustfmt`に相当する公式フォーマッターである
- フォーマットルールはZig言語仕様で定義されており、カスタマイズオプションは提供されていない
- `--ast-check`オプションは`zig ast-check`コマンドと同等の検査を各ファイルに対して実行する

---

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

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

### 推奨読解順序

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

まず、フォーマッター処理で使用される主要なデータ構造を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | fmt.zig | `src/fmt.zig` | Fmt構造体の定義（30-43行目）を確認。seen, any_error, check_ast等のフィールドがフォーマット処理の状態を管理 |
| 1-2 | Ast.zig | `lib/std/zig/Ast.zig` | ZigのAST（抽象構文木）構造。parse関数とrender関数のインターフェースを確認 |

**読解のコツ**: `Fmt`構造体の`SeenMap`（`std.AutoHashMap(Io.File.INode, void)`）はファイルのinode番号をキーとしており、シンボリックリンク経由での重複処理を防止している。

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

処理の起点となる関数を特定する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | main.zig | `src/main.zig` | **318-320行目**: `zig fmt`コマンドのディスパッチ。`@import("fmt.zig").run`を呼び出し |
| 2-2 | fmt.zig | `src/fmt.zig` | **45-205行目**: `run`関数がメインエントリーポイント。引数解析から処理完了まで |

**主要処理フロー**:
1. **45-95行目**: コマンドライン引数の解析ループ
2. **97-158行目**: `--stdin`モードの処理
3. **160-162行目**: 入力ファイルの存在チェック
4. **167-180行目**: Fmt構造体の初期化
5. **184-196行目**: 除外ファイルのseenマップへの登録
6. **198-204行目**: 入力ファイルの処理ループ

#### Step 3: ファイル処理層を理解する

実際のフォーマット処理を行う関数群を読み解く。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | fmt.zig | `src/fmt.zig` | **207-216行目**: `fmtPath`関数。ファイルとディレクトリを振り分け |
| 3-2 | fmt.zig | `src/fmt.zig` | **218-254行目**: `fmtPathDir`関数。ディレクトリの再帰処理 |
| 3-3 | fmt.zig | `src/fmt.zig` | **256-365行目**: `fmtPathFile`関数。単一ファイルのフォーマット処理 |

**主要処理フロー**:
- **262-286行目**: ファイル読み込みとソースコード取得
- **291-298行目**: AST解析（`std.zig.Ast.parse`）
- **300-304行目**: 構文エラーチェック
- **306-342行目**: `--ast-check`時のZIR/ZOIR生成と意味解析
- **348-352行目**: フォーマット生成と差分チェック
- **354-364行目**: 出力処理（checkモードまたはファイル書き込み）

#### Step 4: AST解析・レンダリング層を理解する

Zigの標準ライブラリで提供されるAST処理を確認する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | Ast.zig | `lib/std/zig/Ast.zig` | parse関数：ソースコードからASTを構築 |
| 4-2 | Ast.zig | `lib/std/zig/Ast.zig` | render/renderAlloc関数：ASTから正規フォーマットのコードを生成 |
| 4-3 | AstGen.zig | `lib/std/zig/AstGen.zig` | generate関数：ASTからZIR（Zig Intermediate Representation）を生成し意味解析 |
| 4-4 | ZonGen.zig | `lib/std/zig/ZonGen.zig` | generate関数：ZONファイル用の意味解析 |

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

```
main.zig::mainArgs
    │
    └─ fmt.zig::run (エントリーポイント)
           │
           ├─ 引数解析ループ
           │
           ├─ --stdinモード処理
           │      ├─ std.zig.Ast.parse
           │      ├─ std.zig.AstGen.generate (--ast-check時)
           │      ├─ std.zig.ZonGen.generate (--ast-check時、ZON)
           │      └─ tree.renderAlloc
           │
           └─ fmtPath (ファイル/ディレクトリ処理)
                  │
                  ├─ fmtPathFile (ファイル処理)
                  │      ├─ std.zig.Ast.parse
                  │      ├─ std.zig.AstGen.generate (--ast-check時)
                  │      ├─ tree.render
                  │      └─ dir.createFileAtomic (書き込み)
                  │
                  └─ fmtPathDir (ディレクトリ再帰)
                         └─ fmtPathFile (各ファイル)
```

### データフロー図

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

ファイルパス ───▶ Io.Dir.openFile ───▶ ソースコード
                                              │
                                              ▼
                                    std.zig.Ast.parse
                                              │
                                              ▼
                                           AST構造
                                              │
                          ┌───────────────────┼───────────────────┐
                          │                   │                   │
                          ▼                   ▼                   ▼
                    (エラーあり)       std.zig.AstGen      tree.render
                          │           (--ast-check時)            │
                          ▼                   │                   ▼
                    標準エラー出力            ▼            フォーマット済コード
                                           ZIR                    │
                                              │       ┌───────────┴───────────┐
                                              ▼       │                       │
                                      (エラーチェック) │                       │
                                              │       ▼                       ▼
                                              ▼   ファイル上書き         標準出力
                                        標準エラー出力 (--check時以外)   (--stdin時)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| fmt.zig | `src/fmt.zig` | ソース | fmtコマンドのメイン実装 |
| main.zig | `src/main.zig` | ソース | CLIエントリーポイント、コマンドディスパッチ |
| Ast.zig | `lib/std/zig/Ast.zig` | ソース | Zig AST定義と解析・レンダリング |
| AstGen.zig | `lib/std/zig/AstGen.zig` | ソース | ASTからZIRへの変換（意味解析） |
| ZonGen.zig | `lib/std/zig/ZonGen.zig` | ソース | ZONファイルの意味解析 |
| ErrorBundle.zig | `lib/std/zig/ErrorBundle.zig` | ソース | エラーメッセージの管理と出力 |
