# 機能設計書 12-フォーマット自動検出

## 概要

本ドキュメントは、入力されたスキーマファイルのパスまたはURLから、そのファイル形式（schemarb、postgres、prisma、drizzle、tbls、liam）を自動的に検出する「フォーマット自動検出」機能の設計を記述する。

### 本機能の処理概要

**業務上の目的・背景**：ユーザーがスキーマファイルをLiam ERDに読み込ませる際、ファイル形式を明示的に指定する手間を省くことで、UXを向上させる。特にCLIツールやWeb UIでファイルをドラッグ&ドロップする際に、ユーザーは形式を意識することなくER図を生成できるようになる。

**機能の利用シーン**：
- CLIで`--format`オプションを省略した場合の自動判定
- Web UIでスキーマファイルをアップロードした際の自動判定
- プロジェクト新規作成画面でのスキーマファイル形式の自動選択

**主要な処理内容**：
1. ファイルパスまたはURLからファイル名を抽出
2. ファイル名の完全一致によるフォーマット判定（優先）
3. 拡張子によるフォーマット判定（フォールバック）
4. 判定結果のSupportedFormat型での返却

**関連システム・外部連携**：特になし（純粋な文字列処理）

**権限による制御**：本機能は認証・認可を必要としないユーティリティ機能である。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 8 | プロジェクト新規作成画面 | 補助機能 | スキーマファイル形式の選択 |
| 20 | 公開ERD画面 | 補助機能 | 入力ファイルの形式を自動検出 |

## 機能種別

文字列解析処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| pathOrUrl | string | Yes | スキーマファイルのパスまたはURL | 空文字列でないこと |

### 入力データソース

- ユーザー入力：CLIの`--input`引数
- ファイルシステム：ファイルパス
- Web：URL形式の外部スキーマファイル参照

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| result | SupportedFormat \| undefined | 検出されたフォーマット、または検出不可の場合はundefined |

### SupportedFormat型の定義

```typescript
type SupportedFormat = 'schemarb' | 'postgres' | 'prisma' | 'drizzle' | 'tbls' | 'liam'
```

### 出力先

関数の戻り値として返却される。

## 処理フロー

### 処理シーケンス

```
1. パス/URLからファイル名を抽出
   └─ 最後の'/'以降の文字列を取得し、小文字に変換
2. ファイル名の完全一致チェック
   └─ nameToFormatMapで定義された特定ファイル名との照合
3. 拡張子によるフォーマット判定
   └─ extensionToFormatMapで定義された拡張子との照合
4. 結果の返却
   └─ マッチした場合はSupportedFormat、しなかった場合はundefined
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[ファイル名を抽出]
    B --> C{ファイル名取得成功?}
    C -->|No| D[undefined返却]
    C -->|Yes| E{ファイル名が既知の名前?}
    E -->|Yes| F[対応するフォーマット返却]
    E -->|No| G[拡張子を抽出]
    G --> H{拡張子が既知?}
    H -->|Yes| I[対応するフォーマット返却]
    H -->|No| D
    F --> J[終了]
    I --> J
    D --> J
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-01 | ファイル名優先判定 | 完全なファイル名での判定を拡張子判定より優先する | 常に適用 |
| BR-02 | 大文字小文字無視 | ファイル名の判定は大文字小文字を区別しない | 常に適用 |

### ファイル名からフォーマットへのマッピング

| ファイル名 | フォーマット |
|-----------|-------------|
| schema.rb | schemarb |
| schemafile | schemarb |
| prisma.schema | prisma |
| schema.json | tbls |
| schema.ts | drizzle |
| db.ts | drizzle |
| database.ts | drizzle |
| drizzle.ts | drizzle |

### 拡張子からフォーマットへのマッピング

| 拡張子 | フォーマット |
|-------|-------------|
| rb | schemarb |
| sql | postgres |
| prisma | prisma |
| ts | drizzle |
| js | drizzle |
| json | tbls |

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

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

本機能はデータベースを操作しない（純粋な文字列処理）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 検出不可 | ファイル名・拡張子がマッピングに存在しない | undefinedを返却し、呼び出し元で`--format`の明示的指定を要求 |

### リトライ仕様

リトライ不要（同期的な文字列処理のため）

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

該当なし（データベース操作を行わない）

## パフォーマンス要件

- 処理時間：1ミリ秒以内

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

- パストラバーサル攻撃への対応は不要（ファイル名の抽出のみでファイルアクセスは行わない）

## 備考

- 新しいスキーマ形式をサポートする際は、nameToFormatMapまたはextensionToFormatMapにエントリを追加する
- ドキュメントサイトからも参照されるファイルであり、変更時は注意が必要

---

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

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

### 推奨読解順序

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

まず、サポートされるフォーマットの型定義を理解する。

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | schema.ts | `frontend/packages/schema/src/parser/supportedFormat/schema.ts` | SupportedFormat型の定義（Valibotによるpicklist） |

**読解のコツ**: `v.picklist`はTypeScriptのUnion型を生成するValibotのユーティリティ。

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | index.ts | `frontend/packages/schema/src/parser/supportedFormat/index.ts` | detectFormat関数とSupportedFormat型のエクスポート |

#### Step 3: 検出ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | detectFormat.ts | `frontend/packages/schema/src/parser/supportedFormat/detectFormat.ts` | メインの検出ロジック |

**主要処理フロー**:
- **6-15行目**: nameToFormatMap - ファイル名からフォーマットへのマッピング定義
- **17-24行目**: extensionToFormatMap - 拡張子からフォーマットへのマッピング定義
- **26-45行目**: detectFormat関数 - 検出ロジック本体
- **29行目**: ファイル名の抽出（最後の'/'以降を取得し小文字化）
- **35-37行目**: ファイル名完全一致チェック
- **39-42行目**: 拡張子によるフォールバック判定

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

```
detectFormat(pathOrUrl)
    │
    ├─ pathOrUrl.split('/').pop()?.toLowerCase()
    │      └─ ファイル名抽出と小文字変換
    │
    ├─ nameToFormatMap[fileName]
    │      └─ ファイル名完全一致チェック
    │
    └─ extensionToFormatMap[extension]
           └─ 拡張子によるフォールバック判定
```

### データフロー図

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

pathOrUrl ───▶ split('/').pop() ───▶ fileName
     │                                    │
     │                                    ├─▶ nameToFormatMap ──┐
     │                                    │                     ├─▶ SupportedFormat
     │                                    └─▶ extensionToFormatMap
     │
     └─────────────────────────────────────────────────▶ undefined（検出不可時）
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| detectFormat.ts | `frontend/packages/schema/src/parser/supportedFormat/detectFormat.ts` | ソース | フォーマット自動検出ロジック |
| schema.ts | `frontend/packages/schema/src/parser/supportedFormat/schema.ts` | ソース | SupportedFormat型定義 |
| index.ts | `frontend/packages/schema/src/parser/supportedFormat/index.ts` | ソース | エクスポート定義 |
| detectFormat.test.ts | `frontend/packages/schema/src/parser/supportedFormat/detectFormat.test.ts` | テスト | 検出ロジックの単体テスト |
| runPreprocess.ts | `frontend/packages/cli/src/cli/erdCommand/runPreprocess.ts` | ソース | CLIでの使用例（format未指定時に呼び出し） |
