# 機能設計書 82-共有ウィジェットライブラリ

## 概要

本ドキュメントは、Decap CMSの共有ウィジェットライブラリ（`decap-cms-lib-widgets`パッケージ）の機能設計について記述する。本パッケージは、テンプレート文字列処理、日付パース、フィルタ関数、バリデーション等のウィジェット共有ユーティリティを提供する。

### 本機能の処理概要

**業務上の目的・背景**：Decap CMSの各ウィジェット（文字列、数値、リスト等）やフォーマッタ（スラッグ生成、コミットメッセージ等）は、テンプレート文字列のコンパイル、日付のパース、入力値の範囲バリデーションなどの共通処理を必要とする。これらの共通ロジックを一つのライブラリに集約することで、コードの重複を排除し、一貫性のある動作を保証する。

**機能の利用シーン**：エントリのスラッグ生成時のテンプレート展開（`{{slug}}`、`{{year}}`等）、コミットメッセージのフォーマット、プレビューURLの構築、サマリー表示のフォーマット、リストウィジェットのmin/maxバリデーション、パス内のワイルドカード展開などで使用される。

**主要な処理内容**：
1. テンプレート文字列のコンパイル（`{{変数名}}`形式の変数置換とフィルタ適用）
2. テンプレートフィルタ（upper、lower、date、default、ternary、truncate）
3. 日付パーサー（year、month、day、hour、minute、second）
4. エントリデータからの日付値パース（`parseDateFromEntry`）
5. テンプレート変数の抽出（`extractTemplateVars`）
6. ファイルテンプレートフィールドの追加（dirname、filename、extension）
7. キーからパス配列への変換（ドット記法・ブラケット記法対応）
8. ワイルドカードパスの展開（`expandPath`）
9. リスト値のmin/maxバリデーション（`validateMinMax`）

**関連システム・外部連携**：dayjs（日付処理ライブラリ）、lodash（ユーティリティ）、Node.js pathモジュール

**権限による制御**：本パッケージに権限制御はない。

## 関連画面

本パッケージは直接UIを持たないライブラリであるが、テンプレート処理はエントリ編集画面、コレクション一覧画面のサマリー表示等で間接的に利用される。

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 参照画面 | スラッグ生成、サマリーフォーマット、バリデーションで使用 |
| 3 | コレクション一覧画面 | 参照画面 | エントリサマリーのテンプレート展開で使用 |
| 7 | エントリ新規作成画面 | 参照画面 | 新規エントリのスラッグ生成で使用 |

## 機能種別

ユーティリティ / テンプレート処理 / バリデーション

## 入力仕様

### 入力パラメータ

#### compileStringTemplate

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| template | string | Yes | テンプレート文字列（例: `{{slug}}-{{year}}`) | - |
| date | Date/null/undefined | No | 日付オブジェクト（nullで日付処理無効化） | - |
| identifier | string | No | スラッグ識別子（デフォルト: ''） | - |
| data | Map<string, unknown> | No | テンプレート変数のデータソース | - |
| processor | (value: string) => string | No | 値のカスタム処理関数 | - |

#### validateMinMax

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| t | (key, options) => string | Yes | 翻訳関数 | - |
| fieldLabel | string | Yes | フィールドラベル | - |
| value | List<unknown> | No | バリデーション対象のリスト | - |
| min | number | No | 最小件数 | - |
| max | number | No | 最大件数 | - |

#### expandPath

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| data | Record<string, unknown> | Yes | データオブジェクト | - |
| path | string | Yes | ワイルドカード含むパス（例: `list.*.name`） | - |
| paths | string[] | No | 結果を蓄積する配列 | - |

### 入力データソース

エントリのデータフィールド（Immutable Map）、コレクション設定のテンプレート文字列、日付フィールドの値

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| compiledString | string | テンプレート変数が展開された文字列 |
| templateVars | string[] | テンプレートから抽出された変数名の配列 |
| validationError | {type, message}/undefined | バリデーションエラーオブジェクト（エラーなしの場合undefined） |
| expandedPaths | string[] | ワイルドカードが展開されたパスの配列 |
| fields | Map<string, string> | dirname/filename/extensionが追加されたフィールドマップ |

### 出力先

呼び出し元のフォーマッタ関数（slugFormatter、commitMessageFormatter等）、ウィジェットコンポーネント

## 処理フロー

### 処理シーケンス

```
1. テンプレートコンパイル（compileStringTemplate）
   ├─ テンプレート文字列から{{変数名 | フィルタ}}パターンを検索
   ├─ fields.プレフィックスによる明示的フィールド参照を確認
   ├─ dateParsersによる日付変数（year/month等）の置換
   ├─ slug変数のidentifierでの置換
   ├─ dataマップからの値取得による置換
   └─ フィルタ関数の適用（upper/lower/date/default/ternary/truncate）

2. バリデーション（validateMinMax）
   ├─ min/max/value.sizeの全てが数値かチェック
   ├─ min === maxなら rangeCountExact エラー
   ├─ min > value.sizeなら rangeMin エラー
   └─ max < value.sizeなら rangeMax エラー
```

### フローチャート

```mermaid
flowchart TD
    A[テンプレート文字列入力] --> B[正規表現でパターン検索]
    B --> C{fields.プレフィックスあり?}
    C -->|Yes| D[dataから明示的フィールド値取得]
    C -->|No| E{dateParserに該当?}
    E -->|Yes| F{date引数あり?}
    F -->|Yes| G[日付フォーマット適用]
    F -->|No| H[SLUG_MISSING_REQUIRED_DATEエラー]
    E -->|No| I{slug変数?}
    I -->|Yes| J[identifier値で置換]
    I -->|No| K[dataマップから値取得]
    D --> L{フィルタ指定あり?}
    G --> L
    J --> L
    K --> L
    L -->|Yes| M[フィルタ関数適用]
    L -->|No| N[値をそのまま返却]
    M --> N
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-82-01 | 日付変数必須チェック | テンプレートに日付変数があるがdate引数がundefinedの場合、SLUG_MISSING_REQUIRED_DATEエラーをスロー | dateがnull以外でundefinedの場合 |
| BR-82-02 | fields.プレフィックス優先 | `fields.`プレフィックスが付いた変数名は組み込み変数（slug、year等）より優先される | テンプレート変数がfields.で始まる場合 |
| BR-82-03 | フィルタチェーン | テンプレート変数に`|`で区切られたフィルタが指定可能。processor引数がある場合はフィルタは無視される | テンプレート変数にフィルタが含まれる場合 |
| BR-82-04 | 日付ゼロパディング | month/day/hour/minute/secondは2桁にゼロパディングされる | dateParsers使用時 |

### 計算ロジック

- 日付フォーマット: `formatDate(date)` = `("0" + date).slice(-2)` で2桁にパディング
- truncateフィルタ: `truncate(str, { length: parseInt(match[1]) + omission.length, omission })` でlodashのtruncateを使用

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

該当なし。本パッケージはデータベースやストレージへのアクセスを行わない。

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

なし

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| SLUG_MISSING_REQUIRED_DATE | Error | テンプレートに日付変数があるがdateがundefined | 日付フィールドの設定を確認 |
| RANGE | バリデーションエラー | リスト値がmin/max範囲外 | rangeMin/rangeMax/rangeCount/rangeCountExactメッセージを表示 |

### リトライ仕様

該当なし

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

該当なし

## パフォーマンス要件

テンプレートコンパイルは正規表現ベースの文字列置換であり、特別なパフォーマンス要件はない。

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

- テンプレート変数の値は直接HTMLに挿入される場合があるため、XSS対策は呼び出し側で行う必要がある
- オブジェクト値はJSON.stringifyで文字列化される（getExplicitFieldReplacement）

## 備考

- フィルタのパターンリスト: upper、lower、date('format')、default('value')、ternary('true','false')、truncate(length,'omission')
- dayjsライブラリを日付パースとフォーマットに使用
- expandPathは`.*. `（ワイルドカード）パターンをサポートし、配列要素を展開する

---

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

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

### 推奨読解順序

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

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | index.ts | `packages/decap-cms-lib-widgets/src/index.ts` | stringTemplateとvalidationsの2つのモジュールが公開されていることを確認 |

**読解のコツ**: 本パッケージは非常にシンプルな構造で、stringTemplate.tsとvalidations.tsの2ファイルが中核。

#### Step 2: テンプレート処理エンジンを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | stringTemplate.ts | `packages/decap-cms-lib-widgets/src/stringTemplate.ts` | テンプレートコンパイルの全ロジック |

**主要処理フロー**:
1. **8-38行目**: filtersの定義（upper、lower、date、default、ternary、truncate）
2. **40-43行目**: テンプレートパターンの正規表現定義
3. **50-57行目**: dateParserオブジェクトの定義（year/month/day/hour/minute/second）
4. **59-80行目**: parseDateFromEntry/parseDateFromEntryData - dayjsを使った日付パース
5. **84-108行目**: keyToPathArray - ドット/ブラケット記法をパス配列に変換
6. **110-143行目**: expandPath - ワイルドカード`.*. `パスの展開
7. **147-157行目**: getExplicitFieldReplacement - `fields.`プレフィックスの処理
8. **174-226行目**: compileStringTemplate - テンプレートコンパイルの本体
9. **228-236行目**: extractTemplateVars - テンプレート変数の抽出
10. **246-261行目**: addFileTemplateFields - dirname/filename/extensionの追加

#### Step 3: バリデーション処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | validations.ts | `packages/decap-cms-lib-widgets/src/validations.ts` | min/maxバリデーション |

**主要処理フロー**:
- **5-31行目**: validateMinMax関数 - min/max/sizeの組み合わせでエラーメッセージを決定

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

```
decap-cms-lib-widgets/src/index.ts
    |
    +-- stringTemplate.ts
    |      +-- compileStringTemplate（テンプレートコンパイル本体）
    |      |      +-- getExplicitFieldReplacement（fields.プレフィックス処理）
    |      |      +-- dateParsers（日付変数処理）
    |      |      +-- getFilterFunction（フィルタ適用）
    |      +-- parseDateFromEntry / parseDateFromEntryData
    |      +-- extractTemplateVars
    |      +-- addFileTemplateFields
    |      +-- keyToPathArray
    |      +-- expandPath
    |
    +-- validations.ts
           +-- validateMinMax（min/maxバリデーション）
```

### データフロー図

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

テンプレート文字列 ──────▶ compileStringTemplate ──────▶ 展開済み文字列
 + date                     |
 + identifier               +-- dateParsers（日付置換）
 + data Map                 +-- filters（フィルタ適用）
                            +-- getExplicitFieldReplacement

エントリデータ ──────────▶ parseDateFromEntry ────────▶ Dateオブジェクト
                            (dayjs経由)

テンプレート文字列 ──────▶ extractTemplateVars ───────▶ 変数名配列

リスト値 + min/max ─────▶ validateMinMax ─────────────▶ エラー or undefined
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| index.ts | `packages/decap-cms-lib-widgets/src/index.ts` | ソース | エントリーポイント |
| stringTemplate.ts | `packages/decap-cms-lib-widgets/src/stringTemplate.ts` | ソース | テンプレート処理エンジン |
| validations.ts | `packages/decap-cms-lib-widgets/src/validations.ts` | ソース | バリデーション関数 |
| stringTemplate.spec.js | `packages/decap-cms-lib-widgets/src/__tests__/stringTemplate.spec.js` | テスト | テンプレート処理のテスト |
