# 機能設計書 68-カスタムフォーマット登録

## 概要

本ドキュメントは、Decap CMSのカスタムフォーマット登録機能の設計を定義する。本機能は、グローバルレジストリを経由してカスタムファイルフォーマット（拡張子とフォーマッタ）を登録し、標準フォーマット以外の形式でコンテンツの読み書きを可能にする。

### 本機能の処理概要

カスタムフォーマット登録機能は、Decap CMSの拡張ポイントの一つであり、開発者がYAML/TOML/JSON/Frontmatter以外の独自ファイルフォーマットを登録できるようにする。レジストリにフォーマット名、ファイル拡張子、フォーマッタオブジェクトを登録すると、コレクション設定でその名前を指定してカスタムフォーマットを使用できる。

**業務上の目的・背景**：標準のフォーマットでは対応できない独自のファイル形式（例: XML、CSV、カスタムDSL等）をCMSで管理したい場合に、サードパーティ開発者がフォーマットプラグインを実装できるようにする拡張機構が必要である。

**機能の利用シーン**：CMSの初期化時に`CMS.registerCustomFormat(name, extension, formatter)`を呼び出して独自フォーマットを登録する。コレクション設定の`format`フィールドで登録した名前を指定することで使用される。

**主要な処理内容**：
1. `registerCustomFormat(name, extension, formatter)`でカスタムフォーマットをレジストリに登録
2. `getCustomFormats()`で登録済み全カスタムフォーマットを取得
3. `getCustomFormatsExtensions()`でフォーマット名→拡張子のマッピングを取得
4. `getCustomFormatsFormatters()`でフォーマット名→フォーマッタのマッピングを取得
5. `formatByName()`および`getFormatExtensions()`で標準フォーマットとマージして解決

**関連システム・外部連携**：コンテンツフォーマット対応機能（No.67）のformats.tsと連携し、resolveFormat時にカスタムフォーマットも含めた解決を行う。

**権限による制御**：特になし（初期化時のAPI呼び出しのみ）。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | - | - | 画面との直接的な関連なし。バックグラウンドで動作するフォーマット解決機能 |

## 機能種別

プラグイン登録 / レジストリ管理

## 入力仕様

### 入力パラメータ

#### registerCustomFormat

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| name | string | Yes | フォーマット名（コレクション設定のformat値に一致） | - |
| extension | string | Yes | ファイル拡張子（例: 'xml', 'csv'） | - |
| formatter | Formatter | Yes | fromFile/toFileメソッドを持つフォーマッタオブジェクト | - |

### 入力データソース

- API呼び出し: CMS.registerCustomFormat()によるプログラム的な登録

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| getCustomFormats | Record<string, {extension, formatter}> | 登録済み全カスタムフォーマット |
| getCustomFormatsExtensions | Record<string, string> | フォーマット名→拡張子マッピング |
| getCustomFormatsFormatters | Record<string, Formatter> | フォーマット名→フォーマッタマッピング |

### 出力先

- グローバルレジストリ: registry.formats オブジェクト

## 処理フロー

### 処理シーケンス

```
1. カスタムフォーマット登録
   └─ registerCustomFormat(name, extension, formatter) → registry.formats[name] = { extension, formatter }
2. フォーマット解決時（formats.ts）
   ├─ getCustomFormatsExtensions() → formatExtensionsとマージ
   └─ getCustomFormatsFormatters() → formatByName内のformattersとマージ
3. エントリ読込時
   └─ resolveFormat() → カスタムフォーマッタのfromFile()呼び出し
4. エントリ保存時
   └─ resolveFormat() → カスタムフォーマッタのtoFile()呼び出し
```

### フローチャート

```mermaid
flowchart TD
    A[CMS.registerCustomFormat] --> B["registry.formats[name] = {extension, formatter}"]
    B --> C[フォーマット解決時]
    C --> D[getCustomFormatsFormatters]
    D --> E[formatByName内でマージ]
    E --> F{collection.format === name?}
    F -->|Yes| G[カスタムフォーマッタ使用]
    F -->|No| H[標準フォーマッタ使用]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-68-01 | 上書き可能 | 同名のフォーマットを再登録すると上書きされる | 既存フォーマット名で再登録時 |
| BR-68-02 | 標準フォーマットとの統合 | getCustomFormatsExtensions/Formattersは標準フォーマットと独立に管理され、解決時にマージされる | 常時 |
| BR-68-03 | フォーマッタインターフェース | formatterはfromFile(content: string) => objectとtoFile(data: object, ...) => stringのメソッドを持つ必要がある | 常時 |

### 計算ロジック

特になし。

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

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

該当なし（メモリ上のグローバルレジストリへの登録のみ）。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 未登録フォーマットエラー | resolveFormatで未登録のフォーマット名が指定された場合 | `No formatter available with name: ${name}`をthrow |

### リトライ仕様

リトライ処理は行わない。

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

該当なし。

## パフォーマンス要件

- レジストリの参照はObject.entriesによる線形走査（登録数が少ないため影響なし）

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

- カスタムフォーマッタは外部コードであるため、信頼できるソースからのみ登録すべき
- fromFile/toFileの内部実装は登録者に委ねられるため、パースの安全性は保証されない

## 備考

- レジストリのformatsオブジェクトは空オブジェクト`{}`で初期化される
- カスタムフォーマットはCMSグローバルオブジェクトのregisterCustomFormatメソッドとしてエクスポートされる

---

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

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

### 推奨読解順序

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

レジストリ内のformatsオブジェクトの構造:
```
registry.formats = {
  [formatName: string]: {
    extension: string,     // ファイル拡張子
    formatter: Formatter   // fromFile/toFileを持つオブジェクト
  }
}
```

#### Step 2: レジストリ関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | registry.js | `packages/decap-cms-core/src/lib/registry.js` | registerCustomFormat, getCustomFormats, getCustomFormatsExtensions, getCustomFormatsFormattersの4関数 |

**主要処理フロー**:
- **23行目**: `registry`オブジェクトの初期化（`formats: {}`）
- **289-291行目**: registerCustomFormat - registry.formats[name]に{extension, formatter}を登録
- **293-295行目**: getCustomFormats - registry.formats全体を返却
- **297-301行目**: getCustomFormatsExtensions - name→extensionマッピングをreduce
- **304-308行目**: getCustomFormatsFormatters - name→formatterマッピングをreduce

#### Step 3: フォーマット解決での統合を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | formats.ts | `packages/decap-cms-core/src/formats/formats.ts` | getFormatExtensions()とformatByName()でカスタムフォーマットがマージされる箇所 |

**主要処理フロー**:
- **28-30行目**: getFormatExtensions() - `{ ...formatExtensions, ...getCustomFormatsExtensions() }`
- **52行目**: formatByName内の`...getCustomFormatsFormatters()`でカスタムフォーマッタをマージ

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

```
CMS.registerCustomFormat(name, extension, formatter)
    └─ registry.formats[name] = { extension, formatter }

resolveFormat(collection, entry) [formats.ts]
    ├─ formatByName(name)
    │   └─ { ...standardFormatters, ...getCustomFormatsFormatters() }
    └─ getFormatExtensions()
        └─ { ...formatExtensions, ...getCustomFormatsExtensions() }
```

### データフロー図

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

CMS.registerCustomFormat() ──▶ registry.formats登録
  (name, extension, formatter)      │
                                   ▼
collection.format ────────▶ resolveFormat()
                                   │
                                   ▼
                            formatByName()
                            + getCustomFormatsFormatters()
                                   │
                                   ▼
                            カスタムFormatter ──▶ fromFile/toFile
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| registry.js | `packages/decap-cms-core/src/lib/registry.js` | ソース | カスタムフォーマット登録・取得API |
| formats.ts | `packages/decap-cms-core/src/formats/formats.ts` | ソース | フォーマット解決時のカスタムフォーマット統合 |
