mermaid-graph 0.1.0
Bidirectional conversion between Mermaid diagrams, JSON, and NetworkX graphs
License: MIT
Requires Python: >=3.10

# mermaid-nx

**Mermaid ↔ JSON ↔ NetworkX** の双方向変換ライブラリ。

JSON形式は NetworkX の `node_link_data` を拡張し、Mermaid固有の属性（サブグラフ、classDef、ノード形状、エッジスタイル等）をロスレスに保持します。

## インストール

```bash
pip install -e .
```

依存: `networkx>=3.0`

## クイックスタート

```python
import networkx as nx
import mermaid_graph as mg

mermaid_text = """
flowchart TD
    A([Start]) --> B{Decision}
    B -->|Yes| C[OK]
    B -.->|No| D[Fail]
"""

# Mermaid → JSON
data = mg.mermaid_to_json(mermaid_text)

# JSON → NetworkX
G = mg.to_networkx(data)
print(nx.shortest_path(G, "A", "C"))  # ['A', 'B', 'C']

# NetworkX → Mermaid (round-trip)
print(mg.networkx_to_mermaid(G))
```

## 変換パイプライン

```
Mermaid テキスト
    │  mg.mermaid_to_json()
    ▼
JSON dict (node_link_data 拡張)
    │  mg.to_networkx()
    ▼
NetworkX DiGraph
    │  mg.from_networkx()
    ▼
JSON dict
    │  mg.json_to_mermaid()
    ▼
Mermaid テキスト
```

ショートカット:
- `mg.mermaid_to_networkx(text)` — Mermaid → NetworkX 直接変換
- `mg.networkx_to_mermaid(G)` — NetworkX → Mermaid 直接変換

## JSON フォーマット

NetworkX `node_link_data` 互換。Mermaid固有属性はノード・エッジの追加キーと `graph` セクションの拡張で保持。

```json
{
  "directed": true,
  "multigraph": false,
  "graph": {
    "diagram_type": "flowchart",
    "direction": "TD",
    "class_defs": { "primary": { "fill": "#f9f" } },
    "subgraphs": [
      { "id": "auth", "label": "Authentication", "nodes": ["A", "B"], "subgraphs": [] }
    ],
    "link_styles": { "0": { "stroke": "red" } }
  },
  "nodes": [
    { "id": "A", "label": "Start", "shape": "stadium", "css_class": "primary", "style": null }
  ],
  "links": [
    { "source": "A", "target": "B", "label": null, "line_type": "solid", "arrow": "normal", "link_index": 0 }
  ]
}
```

## 対応するノード形状

| shape 値 | Mermaid 構文 | 見た目 |
|---|---|---|
| `rect` | `[text]` | 長方形 |
| `round_rect` | `(text)` | 角丸 |
| `stadium` | `([text])` | スタジアム |
| `diamond` | `{text}` | ひし形 |
| `hexagon` | `{{text}}` | 六角形 |
| `circle` | `((text))` | 円 |
| `subroutine` | `[[text]]` | 二重枠 |
| `cylinder` | `[(text)]` | 円柱 |
| `asymmetric` | `>text]` | 旗型 |
| `parallelogram` | `[/text/]` | 平行四辺形 |
| `trapezoid` | `[/text\]` | 台形 |
| `double_circle` | `(((text)))` | 二重円 |

## 対応するエッジタイプ

| line_type × arrow | Mermaid |
|---|---|
| solid + normal | `-->` |
| solid + none | `---` |
| solid + circle | `--o` |
| solid + cross | `--x` |
| dotted + normal | `-.->` |
| dotted + none | `-.-` |
| thick + normal | `==>` |
| thick + none | `===` |

## サブグラフ

ネスト対応。NetworkX変換時はノード属性 `_subgraph_path` にサブグラフ所属パスを保持し、JSON復元時にツリー構造を再構築。

```python
# サブグラフのノードをフィルタ
auth_nodes = [n for n, d in G.nodes(data=True)
              if "auth" in d.get("_subgraph_path", [])]
```

## プログラムからグラフ構築

```python
graph = mg.MermaidGraph(
    direction="LR",
    class_defs={"important": {"fill": "#faa"}},
    subgraphs=[mg.Subgraph(id="pipeline", label="Data Pipeline", nodes=["a", "b"])],
    nodes=[
        mg.MermaidNode(id="a", label="Ingest", shape="stadium", css_class="important"),
        mg.MermaidNode(id="b", label="Load", shape="cylinder"),
    ],
    links=[mg.MermaidLink(source="a", target="b", line_type="thick")],
)
print(mg.json_to_mermaid(graph.to_dict()))
```

## テスト

```bash
uv run --with pytest pytest
```

## ライセンス

MIT