# 機能設計書 80-ウィジェット値シリアライザー

## 概要

本ドキュメントは、ウィジェットごとの値シリアライズ/デシリアライズ処理をカスタム登録する機能の設計を記述する。

### 本機能の処理概要

本機能は、特定のウィジェットタイプに対してカスタムのシリアライズ（エディタ内部値→ファイル保存形式への変換）およびデシリアライズ（ファイル保存形式→エディタ内部値への変換）処理をグローバルレジストリに登録・取得する仕組みを提供する。

**業務上の目的・背景**：CMSのウィジェットは、エディタ内部で扱う値の形式とファイルに保存する形式が異なる場合がある。例えば、リストウィジェットは内部ではImmutable.jsのListオブジェクトだが、ファイルにはプレーンなJSON配列として保存する必要がある。カスタムウィジェットでも同様に独自のシリアライズ/デシリアライズロジックが必要になる場合があり、本機能はその登録手段を提供する。

**機能の利用シーン**：
- カスタムウィジェットがファイル保存時に値を特定のフォーマットに変換する必要がある場合
- ファイルからの読み込み時にウィジェット固有の値に変換する必要がある場合
- 複雑なデータ構造を持つウィジェットの値変換ロジックをカスタマイズする場合

**主要な処理内容**：
1. **シリアライザー登録（registerWidgetValueSerializer）**: ウィジェット名とシリアライザーオブジェクトのペアをレジストリに登録
2. **シリアライザー取得（getWidgetValueSerializer）**: ウィジェット名で対応するシリアライザーオブジェクトを取得

**関連システム・外部連携**：レジストリ（registry.js）と連携。エントリのシリアライズ処理（formats/、entries.ts等）で使用される。

**権限による制御**：シリアライザー登録はグローバルAPIとして公開されており、権限制御はない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 参照画面 | エントリ保存時にウィジェット値のシリアライズが実行される |
| 7 | エントリ新規作成画面 | 参照画面 | 新規エントリ保存時にウィジェット値のシリアライズが実行される |

## 機能種別

プラグイン登録 / データ変換

## 入力仕様

### 入力パラメータ

**registerWidgetValueSerializer**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| widgetName | string | Yes | 対象ウィジェット名 | - |
| serializer | object | Yes | シリアライザーオブジェクト（serialize/deserializeメソッドを持つ） | - |

**getWidgetValueSerializer**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| widgetName | string | Yes | 対象ウィジェット名 | - |

### 入力データソース

- CMS.registerWidgetValueSerializer() API経由で登録される
- カスタムウィジェットパッケージからの登録

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| serializer | object | シリアライザーオブジェクト（serialize/deserializeメソッド） |

### 出力先

registry.widgetValueSerializers[widgetName]（インメモリ）に格納。getWidgetValueSerializer(widgetName)で取得可能。

## 処理フロー

### 処理シーケンス

```
1. registerWidgetValueSerializer(widgetName, serializer)呼び出し
   └─ registry.widgetValueSerializers[widgetName]にserializerを格納
2. エントリ保存時
   └─ getWidgetValueSerializer(widgetName)でシリアライザーを取得
   └─ serializer.serialize(value)でファイル保存形式に変換
3. エントリ読み込み時
   └─ getWidgetValueSerializer(widgetName)でシリアライザーを取得
   └─ serializer.deserialize(rawValue)でエディタ内部値に変換
```

### フローチャート

```mermaid
flowchart TD
    A[CMS.registerWidgetValueSerializer] --> B[registry.widgetValueSerializers に格納]
    B --> C[シリアライザー登録完了]

    D[エントリ保存] --> E[getWidgetValueSerializer]
    E --> F{シリアライザーあり?}
    F -->|Yes| G[serializer.serialize 実行]
    F -->|No| H[デフォルトのシリアライズ]
    G --> I[変換済み値をファイルに保存]
    H --> I

    J[エントリ読み込み] --> K[getWidgetValueSerializer]
    K --> L{シリアライザーあり?}
    L -->|Yes| M[serializer.deserialize 実行]
    L -->|No| N[デフォルトのデシリアライズ]
    M --> O[変換済み値をエディタに表示]
    N --> O
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-80-01 | 名前キー登録 | シリアライザーはwidgetNameをキーとしてプレーンオブジェクトに格納される | registerWidgetValueSerializer時 |
| BR-80-02 | 上書き可能 | 同一widgetNameで再登録した場合、既存のシリアライザーが上書きされる | 同名で再登録時 |
| BR-80-03 | undefined返却 | 登録されていないwidgetNameに対するgetWidgetValueSerializerはundefinedを返す | 未登録ウィジェット指定時 |

### 計算ロジック

特になし。

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

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

本機能はインメモリのレジストリオブジェクトへの登録であり、データベース操作は行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ランタイムエラー | serializerがserialize/deserializeメソッドを持たない場合 | 呼び出し時にTypeErrorが発生する |

### リトライ仕様

リトライは不要。

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

トランザクションは存在しない。

## パフォーマンス要件

- シリアライザーの登録・取得はO(1)のハッシュマップ操作
- serialize/deserialize処理の実行時間はシリアライザーの実装に依存する

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

- シリアライザーはウィジェットの値を変換する関数であり、悪意のあるシリアライザーによるデータ改竄のリスクがある
- deserializeでファイルから読み込んだ値を変換する際、信頼できないデータの処理に注意が必要

## 備考

- widgetValueSerializersはプレーンオブジェクト（{} ）で管理されており、他のレジストリ領域と同様のキー-値マッピング
- シリアライザーオブジェクトのインターフェースはregistry.js内では定義されておらず、利用側（エントリのシリアライズ処理）でserialize/deserializeメソッドの存在が暗黙的に期待される
- registerWidgetValueSerializer / getWidgetValueSerializerはバリデーション処理を持たず、純粋なキー-値の格納・取得のみを行う

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | registry.js | `packages/decap-cms-core/src/lib/registry.js` | registry.widgetValueSerializersの初期化と構造 |

**読解のコツ**: widgetValueSerializersはシンプルなキー-値のプレーンオブジェクト。バリデーションやデフォルト値設定はない。

**主要処理フロー**:
- **30行目**: widgetValueSerializers: {} - 空オブジェクトとして初期化

#### Step 2: 登録・取得ロジックを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | registry.js | `packages/decap-cms-core/src/lib/registry.js` | registerWidgetValueSerializer/getWidgetValueSerializerの実装 |

**主要処理フロー**:
- **190-192行目**: registerWidgetValueSerializer(widgetName, serializer) - registry.widgetValueSerializers[widgetName] = serializer
- **193-195行目**: getWidgetValueSerializer(widgetName) - return registry.widgetValueSerializers[widgetName]

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

```
CMS.registerWidgetValueSerializer(widgetName, serializer)
    |
    +-- registerWidgetValueSerializer(widgetName, serializer) [registry.js]
            +-- registry.widgetValueSerializers[widgetName] = serializer

エントリシリアライズ処理
    |
    +-- getWidgetValueSerializer(widgetName) [registry.js]
            +-- return registry.widgetValueSerializers[widgetName]
            |
            +-- serializer.serialize(value) / serializer.deserialize(rawValue)
```

### データフロー図

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

registerWidgetValueSerializer -->  レジストリ格納               -->  widgetValueSerializers
  (widgetName, serializer)         [widgetName] = serializer        (インメモリ)

エントリ値                  -->  getWidgetValueSerializer      -->  serializer
  (ウィジェット内部値)             (widgetName検索)
                                        |
                                 serializer.serialize(value)    -->  ファイル保存用値

ファイル値                  -->  serializer.deserialize(raw)   -->  ウィジェット内部値
  (ファイルから読み込み)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| registry.js | `packages/decap-cms-core/src/lib/registry.js` | ソース | registerWidgetValueSerializer/getWidgetValueSerializer実装 |
