# 機能設計書 79-Remarkプラグイン

## 概要

本ドキュメントは、Markdownパーサー（Remark）にカスタムプラグインを追加登録する機能の設計を記述する。

### 本機能の処理概要

本機能は、Markdownウィジェットで使用されるRemarkパーサーに対して、カスタムプラグインを登録・取得する仕組みを提供する。Remarkプラグインにより、Markdownの構文解析やHTML変換の振る舞いをカスタマイズできる。

**業務上の目的・背景**：標準のMarkdownパーサーでは対応できない独自記法（カスタムディレクティブ、特殊なシンタックス等）をサポートする必要がある場合、Remarkプラグインを追加することで対応できる。これにより、プロジェクト固有のMarkdown拡張をCMSに組み込める。

**機能の利用シーン**：
- カスタムMarkdown記法（例: :::note ... ::: のようなディレクティブ）のパース
- Markdown→HTML変換時のカスタム変換ルールの追加
- Markdownエディタのプレビュー表示のカスタマイズ

**主要な処理内容**：
1. **Remarkプラグイン登録（registerRemarkPlugin）**: unified.jsのPluggable型に準拠したプラグインをレジストリの配列に追加
2. **Remarkプラグイン取得（getRemarkPlugins）**: 登録済みの全Remarkプラグインを配列として返す

**関連システム・外部連携**：レジストリ（registry.js）、unified/remark（Markdownパーサーエコシステム）、Markdownウィジェット（decap-cms-widget-markdown）と連携する。

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

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 6 | エントリ編集画面 | 参照画面 | Markdownウィジェットでの編集・プレビュー時にRemarkプラグインが適用される |
| 7 | エントリ新規作成画面 | 参照画面 | 新規エントリのMarkdown編集時にRemarkプラグインが適用される |

## 機能種別

プラグイン登録 / パーサー拡張

## 入力仕様

### 入力パラメータ

**registerRemarkPlugin**

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| plugin | Pluggable (unified.js) | Yes | Remarkプラグイン。unified.jsのPluggable型に準拠 | - |

### 入力データソース

- CMS.registerRemarkPlugin() API経由で登録される
- 外部JavaScriptからの呼び出し

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| remarkPlugins | Array<Pluggable> | 登録済みRemarkプラグインの配列 |

### 出力先

registry.remarkPlugins配列（インメモリ）に格納。getRemarkPlugins()で取得可能。

## 処理フロー

### 処理シーケンス

```
1. registerRemarkPlugin(plugin)呼び出し
   └─ registry.remarkPlugins配列にpush
2. Markdownウィジェット初期化時
   └─ getRemarkPlugins()で登録済みプラグインを取得
   └─ remarkパーサーのuse()メソッドでプラグインを適用
```

### フローチャート

```mermaid
flowchart TD
    A[CMS.registerRemarkPlugin] --> B[registry.remarkPlugins.push]
    B --> C[プラグイン登録完了]
    D[Markdownウィジェット初期化] --> E[getRemarkPlugins]
    E --> F[remark.use でプラグイン適用]
    F --> G[カスタム構文解析/変換が有効化]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-79-01 | 配列追加 | プラグインはremarkPlugins配列の末尾にpushで追加される | registerRemarkPlugin時 |
| BR-79-02 | 重複チェックなし | 同一プラグインの重複登録に対するバリデーションは行われない | 常時 |
| BR-79-03 | 順序保証 | プラグインは登録順に配列に格納され、適用順序は登録順に依存する | 常時 |

### 計算ロジック

特になし。

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

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

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

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | ランタイムエラー | Pluggable型に準拠しないプラグインを登録した場合 | remark.use()実行時にエラーが発生する |

### リトライ仕様

リトライは不要。

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

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

## パフォーマンス要件

- プラグイン登録はO(1)のpush操作
- 多数のプラグインを登録した場合、Markdownパース処理の遅延が発生する可能性がある

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

- Remarkプラグインはmarkdownの構文解析ツリー（AST）を操作できるため、悪意のあるプラグインによるデータ改竄のリスクがある
- プラグイン内でのHTML生成にはXSSリスクが伴う

## 備考

- remarkPluginsはプレーンな配列で管理されており、他のレジストリ領域（ImmutableMap、プレーンオブジェクト等）とは異なる
- unified.jsのPluggable型は関数または[関数, オプション]のタプルの両方をサポートする
- JSDocコメントでPluggable型が明示されている（@typedef {import('unified').Pluggable} RemarkPlugin）

---

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

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

### 推奨読解順序

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

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

**読解のコツ**: JSDocコメントで@typedef {import('unified').Pluggable} RemarkPluginが定義されている。unified.jsのPluggable型はRemarkのプラグインシステムの基本型。

**主要処理フロー**:
- **29行目**: remarkPlugins: [] - 空配列として初期化

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

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

**主要処理フロー**:
- **177行目**: JSDoc: @typedef {import('unified').Pluggable} RemarkPlugin
- **178行目**: JSDoc: @type {(plugin: RemarkPlugin) => void}
- **179-181行目**: registerRemarkPlugin(plugin) - registry.remarkPlugins.push(plugin)
- **182行目**: JSDoc: @type {() => Array<RemarkPlugin>}
- **183-185行目**: getRemarkPlugins() - return registry.remarkPlugins

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

```
CMS.registerRemarkPlugin(plugin)
    |
    +-- registerRemarkPlugin(plugin) [registry.js]
            +-- registry.remarkPlugins.push(plugin)

Markdownウィジェット初期化
    |
    +-- getRemarkPlugins() [registry.js]
            +-- return registry.remarkPlugins
            |
            +-- remark.use(plugin) [Markdownウィジェット内]
```

### データフロー図

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

Remarkプラグイン            -->  registerRemarkPlugin          -->  registry.remarkPlugins
  (Pluggable型)                  (配列にpush)                      (配列に格納)
                                        |
Markdownウィジェット        -->  getRemarkPlugins              -->  プラグイン配列
                                 (配列参照を返す)                    |
                                                                    v
Markdownテキスト            -->  remark.use(plugins)           -->  カスタムAST変換
                                 (プラグイン適用)                   Markdown→HTML
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| registry.js | `packages/decap-cms-core/src/lib/registry.js` | ソース | registerRemarkPlugin/getRemarkPlugins実装 |
| decap-cms-widget-markdown | `packages/decap-cms-widget-markdown/` | パッケージ | Remarkプラグインの適用先であるMarkdownウィジェット |
