# mdforge 設計書 v0.1

## 1. 目的

**mdforge** は、LLM に独自拡張 Markdown を書かせ、それを厳密に検証し、最終的に DOM 構造へコンパイルする Rust ライブラリである。

## 2. 解決したい課題

生成 AI に Markdown を書かせると、以下の問題が発生する。

- 構文が壊れる
- 未定義参照が出る
- 値の型が間違う
- 表現を制御できない

mdforge は以下の仕組みでこれを制御する。

- 拡張構文の定義
- 型付き引数検証
- dynamic enum 検証
- 構造化エラー
- DOM 出力

## 3. 非目標

- Markdown 完全再実装はしない
- HTML レンダリングエンジンにはならない
- フロントエンドフレームワークにはならない

## 4. 全体アーキテクチャ

```text
拡張Markdown
  ↓
parse（ブロック・インライン抽出）
  ↓
validate（構文 + 型）
  ↓
eval（dynamic enum）
  ↓
render_dom（VNode生成）
  ↓
to_html / JSON / React変換
```

## 5. 言語仕様

### 5.1 ブロック拡張

構文:

```markdown
:::name key=value key=value
body
:::
```

条件:

- 行頭から開始
- 終端は単独 `:::`
- 本文内にインライン拡張を許可

### 5.2 インライン拡張

構文:

```markdown
{name key=value key=value}
```

条件:

- 通常 Markdown 内どこでも出現可能
- ネストは初期バージョンでは禁止
- 自己完結型のみ

### 5.3 引数型

```rust
pub enum ArgType {
    Int,
    String,
    StaticEnum(&'static [&'static str]),
    DynamicEnum(&'static str),
}
```

検証段階:

| 型 | 検証タイミング |
| --- | --- |
| Int | validate |
| String | validate |
| StaticEnum | validate |
| DynamicEnum | eval |

## 6. AST 設計

### 6.1 Document

```rust
pub struct Document {
    pub nodes: Vec<Node>,
}
```

### 6.2 Node

```rust
pub enum Node {
    Markdown(Vec<MdEvent>),
    Block(BlockNode),
}
```

### 6.3 BlockNode

```rust
pub struct BlockNode {
    pub name: String,
    pub args: HashMap<String, ArgValue>,
    pub body: Vec<Node>,
    pub span: Span,
}
```

### 6.4 Inline

```rust
pub struct InlineExt {
    pub name: String,
    pub args: HashMap<String, ArgValue>,
    pub span: Span,
}
```

## 7. DOM 中間表現

### 7.1 VNode

```rust
pub enum VNode {
    Element(VElement),
    Text(String),
}
```

### 7.2 VElement

```rust
pub struct VElement {
    pub tag: String,
    pub attrs: Vec<(String, String)>,
    pub children: Vec<VNode>,
}
```

## 8. Renderer 設計

```rust
pub trait DomRenderer {
    fn render_block(
        &self,
        block: &BlockNode,
        ctx: &EvalContext,
        children: Vec<VNode>,
    ) -> VNode;

    fn render_inline(
        &self,
        inline: &InlineExt,
        ctx: &EvalContext,
    ) -> VNode;
}
```

## 9. 検証とフィードバック

### 9.1 Diagnostic

```rust
pub struct Diagnostic {
    pub level: Level,
    pub code: ErrorCode,
    pub message: String,
    pub span: Span,
    pub suggestion: Option<String>,
}
```

### 9.2 ErrorCode

```rust
pub enum ErrorCode {
    UnknownBlock,
    UnknownInline,
    MissingRequiredArg,
    UnknownArg,
    InvalidType,
    InvalidStaticEnumValue,
    InvalidDynamicEnumValue,
    BlockNotClosed,
}
```

## 10. AI 指示用シグネチャ生成

```rust
pub fn signature(&self) -> String;
```

出力例:

```text
Block: card
:::card title=<string> level=<int?>
Body: markdown

Inline: badge
{badge level=<int>}
```

## 11. 実装ガイドライン（AI / 開発者向け）

LLM / AGENT がコードを生成・編集する際は、以下を推奨する。

- 1 ファイルが過大化しないよう、責務ごとに適切な粒度で分割する。
- 分割時は同一レイヤへフラットに並べるだけの構成を避け、最低限の階層設計（同一階層の分割は 1 段階までを目安）を行う。
- 同じ振る舞いが複数箇所で現れる場合は、重複実装を増やさずインタフェース（trait / 抽象）を切り出して再利用性を確保する。
- 可読性を優先し、`cargo fmt` と `cargo clippy` を適宜実行して、命名・構造・警告の品質を維持する。

Spec と常に一致する。

## 12. DynamicEnum 評価

```rust
pub struct EvalContext {
    pub dynamic_values: HashMap<String, HashSet<String>>,
}
```

eval 段階で:

- DynamicEnum 値の存在チェック
- エラー時に候補一覧提示

## 13. 公開 API

```rust
let forge = Forge::builder()
    .block("card")
        .arg("title", ArgType::String.required())
        .body_markdown()
        .register()
    .inline("badge")
        .arg("level", ArgType::Int.required())
        .register()
    .build();

let doc = forge.parse(input)?;
forge.validate(&doc)?;
let ctx = forge.eval(&doc, &dynamic_ctx)?;
let dom = forge.render_dom(&doc, &ctx, &renderer)?;
```

## 14. 将来拡張

- typed_block
- inline container 形式
- custom ArgType validator
- JSON ターゲット
- React 用 VNode 出力
- WebAssembly 対応

## 15. 成功基準

mdforge は:

- LLM 出力を確実に検証できる
- 拡張構文を厳密に制御できる
- HTML 以外のターゲットへ拡張可能
- 単なる Markdown 拡張ではなく「DSL コンパイラ」である

## 最終定義

mdforge は、Markdown を基盤とした、型安全・評価可能・DOM 出力可能な拡張 DSL コンパイラ。
