# 機能設計書：9-ドキュメント生成

## 1. 機能概要

### 1.1 目的
本機能は、NimソースコードからHTML/LaTeX/JSON形式のドキュメントを自動生成するドキュメンテーションジェネレータである。docコマンドで呼び出され、ソースコード内のドキュメントコメント（##で始まるコメント）を解析し、RST/Markdown記法をサポートしながらAPIリファレンスを生成する。

### 1.2 機能範囲
- Nimソースコード（.nim）のドキュメント生成
- RST/Markdownファイル（.rst/.md）のHTML/LaTeX変換
- JSON形式でのドキュメント出力
- runnableExamplesの実行とコード例の埋め込み
- クロスリファレンス（相互参照）の自動生成
- インデックスファイルの生成

### 1.3 関連モジュール
| モジュール | 役割 |
|-----------|------|
| docgen.nim | ドキュメント生成メインモジュール |
| packages/docutils/rst.nim | RST解析 |
| packages/docutils/rstgen.nim | RST→HTML/LaTeX変換 |
| packages/docutils/rstast.nim | RST AST定義 |
| packages/docutils/rstidx.nim | インデックス管理 |
| docgen2.nim | セマンティック解析付きドキュメント生成 |


## 2. アーキテクチャ設計

### 2.1 システム構成図
```
+------------------+
|   doc コマンド   |
+--------+---------+
         |
         v
+------------------+     +------------------+
|  newDocumentor   |---->|   TDocumentor    |
+--------+---------+     +--------+---------+
         |                        |
         v                        v
+------------------+     +------------------+
|   parseRst       |     |   RstGenerator   |
| (RST/MD解析)     |     | (HTML/LaTeX生成) |
+--------+---------+     +--------+---------+
         |                        |
         v                        v
+------------------+     +------------------+
|   generateDoc    |     |  finishGenerate  |
|  (AST走査)       |     |   Doc (Pass 2)   |
+--------+---------+     +--------+---------+
         |                        |
         v                        v
+------------------+     +------------------+
|   genItem        |     |   writeOutput    |
| (シンボル処理)   |     | (ファイル出力)   |
+------------------+     +------------------+
```

### 2.2 データフロー
```
Nim ソースコード (.nim)
        |
        v
+------------------+
|   AST 解析       |
| (parser/sem)     |
+--------+---------+
        |
        v
+------------------+
| ドキュメント     |
| コメント抽出     |
| (genComment)     |
+--------+---------+
        |
        v
+------------------+
| RST/MD 解析      |
| (parseRst)       |
+--------+---------+
        |
        v
+------------------+
| シンボル収集     |
| (genItem)        |
+--------+---------+
        |
        v
+------------------+
| RST Pass 2       |
| (リンク解決)     |
+--------+---------+
        |
        v
+------------------+
| HTML/LaTeX 生成  |
| (renderRstToOut) |
+--------+---------+
        |
        v
出力ファイル (.html/.tex/.json)
```


## 3. データ構造設計

### 3.1 主要データ型

#### TDocumentor型（ドキュメンテータ本体）
```nim
# compiler/docgen.nim 79-110行目
TDocumentor = object of rstgen.RstGenerator
  modDescPre: ItemPre     # モジュール説明（未確定）
  modDescFinal: string    # モジュール説明（確定後）
  module: PSym            # 対象モジュールシンボル
  modDeprecationMsg: string  # 廃止メッセージ
  section: ModSections    # 各シンボル種別のセクション
  tocSimple: array[TSymKind, seq[TocItem]]  # 単純TOC
  tocTable: array[TSymKind, Table[string, seq[TocItem]]]  # グループ化TOC
  toc2: TocSectionsFinal  # 中間TOC
  toc: TocSectionsFinal   # 最終TOC
  indexValFilename: string
  analytics: string       # Google Analytics
  seenSymbols: StringTableRef  # 重複防止用
  jEntriesPre: seq[JsonItem]   # JSON出力用（未確定）
  jEntriesFinal: JsonNode      # JSON出力用（確定後）
  types: TStrTable        # 型テーブル
  sharedState: PRstSharedState  # RST共有状態
  standaloneDoc: bool     # スタンドアロンドキュメントか
  conf*: ConfigRef        # コンパイラ設定
  cache*: IdentCache      # 識別子キャッシュ
  exampleCounter: int     # 例のカウンタ
  emitted: IntSet         # 出力済みシンボル
  thisDir*: AbsoluteDir   # 出力ディレクトリ
  exampleGroups: OrderedTable[string, ExampleGroup]  # 例グループ
  wroteSupportFiles*: bool  # サポートファイル出力済み
  nimToRstFid: Table[lineinfos.FileIndex, rstast.FileIndex]  # FileIndex変換
```

#### Item型（ドキュメント項目）
```nim
# compiler/docgen.nim 48-58行目
Item = object
  descRst: ItemPre       # 項目説明（RST）
  substitutions: seq[string]  # 置換変数
  sortName: string       # ソート用名前
  info: rstast.TLineInfo # 位置情報
  anchor: string         # HTMLアンカー
  name: string           # 短い名前
  detailedName: string   # 詳細名（シグネチャ付き）
```

#### ItemFragment型（フラグメント）
```nim
# compiler/docgen.nim 40-47行目
ItemFragment = object
  case isRst: bool
  of true:
    rst: PRstNode        # RSTノード
  of false:
    str: string          # 生成済みマークアップ
```

#### ModSection型（モジュールセクション）
```nim
# compiler/docgen.nim 60-63行目
ModSection = object
  secItems: Table[string, seq[Item]]  # 名前→項目マップ
  finalMarkup: string    # 最終マークアップ
```

#### ExampleGroup型（例グループ）
```nim
# compiler/docgen.nim 69-74行目
ExampleGroup = ref object
  rdoccmd: string        # runnableExamplesの引数
  docCmd: string         # ユーザー設定のdocCmd
  code: string           # インポート含むコード
  index: int             # グループインデックス
```


## 4. 処理フロー設計

### 4.1 ドキュメント生成フロー

#### newDocumentor（初期化）
```nim
# compiler/docgen.nim 324-421行目
proc newDocumentor*(filename: AbsoluteFile; cache: IdentCache; conf: ConfigRef,
                    outExt: string = HtmlExt, module: PSym = nil,
                    standaloneDoc = false, preferMarkdown = true,
                    hasToc = true): PDoc =
  # 1. 出力ファイルパスを計算
  let destFile = getOutFile2(conf, presentationPath(conf, filename), outExt, false).string

  # 2. TDocumentor初期化
  new(result)
  result.module = module
  result.conf = conf
  result.cache = cache
  result.standaloneDoc = standaloneDoc

  # 3. RST解析オプション設定
  var options = {roSupportRawDirective, roSupportMarkdown, roSandboxDisabled}
  if preferMarkdown:
    options.incl roPreferMarkdown
  if not standaloneDoc:
    options.incl roNimFile

  # 4. RST共有状態初期化
  result.sharedState = newRstSharedState(
      options, filename.string,
      docgenFindFile, docgenFindRefFile, compilerMsgHandler, hasToc)

  # 5. RstGenerator初期化
  initRstGenerator(result[], (if conf.isLatexCmd: outLatex else: outHtml),
                   conf.configVars, filename.string,
                   docgenFindFile, compilerMsgHandler)

  # 6. Google Analytics設定
  if conf.configVars.hasKey("doc.googleAnalytics"):
    result.analytics = "..." # Analytics JavaScript

  # 7. テストスニペットコールバック設定
  result.onTestSnippet = proc(...) = ...
```

#### generateDoc（メイン生成処理）
```nim
# compiler/docgen.nim 1372-1431行目
proc generateDoc*(d: PDoc, n, orig: PNode, config: ConfigRef, docFlags: DocFlags = kDefault) =
  # ASTノード種別に応じた処理
  case n.kind
  of nkPragma:
    # プラグマ処理（deprecated、doctype）
    let pragmaNode = findPragma(n, wDeprecated)
    d.modDeprecationMsg.add(genDeprecationMsg(d, pragmaNode))

  of nkCommentStmt:
    # モジュール説明コメント
    d.modDescPre.add(genComment(d, n))

  of nkProcDef, nkFuncDef:
    # プロシージャ/関数ドキュメント
    when useEffectSystem: documentRaises(d.cache, n)
    genItem(d, n, n[namePos], skProc, docFlags)

  of nkMethodDef:
    genItem(d, n, n[namePos], skMethod, docFlags)

  of nkIteratorDef:
    genItem(d, n, n[namePos], skIterator, docFlags)

  of nkMacroDef:
    genItem(d, n, n[namePos], skMacro, docFlags)

  of nkTemplateDef:
    genItem(d, n, n[namePos], skTemplate, docFlags)

  of nkConverterDef:
    genItem(d, n, n[namePos], skConverter, docFlags)

  of nkTypeSection, nkVarSection, nkLetSection, nkConstSection:
    # 型/変数/定数セクション
    for i in 0..<n.len:
      if n[i].kind != nkCommentStmt:
        genItem(d, n[i], n[i][0], succ(skType, ord(n.kind)-ord(nkTypeSection)), docFlags)

  of nkStmtList:
    # 文リストの再帰処理
    for i in 0..<n.len:
      generateDoc(d, n[i], orig, config)

  of nkImportStmt:
    # インポート依存関係の追跡
    for it in n: traceDeps(d, it)

  of nkExportStmt:
    # エクスポートシンボルの処理
    for it in n:
      if it.kind == nkSym:
        exportSym(d, it.sym)
```

#### genItem（シンボル項目生成）
```nim
# compiler/docgen.nim 1048-1166行目
proc genItem(d: PDoc, n, nameNode: PNode, k: TSymKind, docFlags: DocFlags, nonExports: bool = false) =
  # 1. 可視性チェック
  if (docFlags != kForceExport) and not isVisible(d, nameNode): return

  # 2. 名前とドキュメント取得
  let name = getName(nameNode)
  var plainDocstring = getPlainDocstring(n)
  var comm: ItemPre = default(ItemPre)
  if n.kind in routineDefs:
    getAllRunnableExamples(d, n, comm)
  else:
    comm.add genRecComment(d, n)

  # 3. アンカー生成
  inc(d.id)
  let cleanPlainSymbol = renderPlainSymbolName(nameNode)
  let complexSymbol = complexName(k, n, cleanPlainSymbol)
  let symbolOrId = d.newUniquePlainSymbol(complexSymbol)

  # 4. HTMLレンダリング
  var result = ""
  nodeToHighlightedHtml(d, n, result, renderFlags, symbolOrIdEnc)

  # 5. Item登録
  d.section[k].secItems.mgetOrPut(cleanPlainSymbol, newSeq[Item]()).add Item(
    descRst: comm,
    sortName: sortName,
    anchor: symbolOrId,
    name: name,
    detailedName: detailedName,
    ...)

  # 6. TOC項目追加
  d.tocSimple[k].add TocItem(...)
  d.tocTable[k].mgetOrPut(cleanPlainSymbol, newSeq[TocItem]()).add TocItem(...)

  # 7. インデックス登録
  setIndexTerm(d[], ieNim, htmlFile = external, id = symbolOrId, term = name, ...)
```

#### finishGenerateDoc（Pass 2処理）
```nim
# compiler/docgen.nim 1460-1571行目
proc finishGenerateDoc*(d: var PDoc) =
  # 1. ファイルマップコピー
  d.filenames = d.sharedState.filenames

  # 2. 最初のRSTフラグメント取得（タイトル用）
  var firstRst = PRstNode(nil)
  for fragment in d.modDescPre:
    if fragment.isRst:
      firstRst = fragment.rst
      break

  # 3. Pass 2準備
  d.hasToc = d.hasToc or d.sharedState.hasToc
  let importdoc = optGenIndexOnly notin d.conf.globalOptions and
                  optNoImportdoc notin d.conf.globalOptions
  preparePass2(d.sharedState, firstRst, importdoc)

  # 4. オーバーロードグループにアンカー追加
  for k in TSymKind:
    if k in routineKinds:
      for plainName, overloadChoices in d.section[k].secItems:
        if overloadChoices.len > 1:
          let refn = overloadGroupName(plainName, k)
          addAnchorNim(d.sharedState, external=false, refn, tooltip, ...)

  # 5. 各セクションのRST解決とレンダリング
  proc renderItemPre(d: PDoc, fragments: ItemPre, result: var string) =
    for f in fragments:
      case f.isRst:
      of true:
        var resolved = resolveSubs(d.sharedState, f.rst)
        renderRstToOut(d[], resolved, result)
      of false:
        result &= f.str

  # 6. セクション処理
  for k in TSymKind:
    for plainName, overloadChoices in d.section[k].secItems:
      for item in overloadChoices.sorted(cmp):
        var itemDesc: string = ""
        renderItemPre(d, item.descRst, itemDesc)
        nameContent.add(getConfigVar(d.conf, "doc.item") % ...)

  # 7. モジュール説明レンダリング
  renderItemPre(d, d.modDescPre, d.modDescFinal)

  # 8. インデックスタイトル設定
  setIndexTitle(d, useMetaTitle = d.standaloneDoc)
  completePass2(d.sharedState)
```


### 4.2 runnableExamplesの処理

```nim
# compiler/docgen.nim 622-691行目
proc prepareExample(d: PDoc; n: PNode, topLevel: bool): tuple[rdoccmd: string, code: string] =
  # 1. rdoccmd引数の取得
  var rdoccmd = ""
  if n.len == 3:
    let n1 = n[1]
    if n1.kind in nkStrKinds:
      rdoccmd = n1.strVal

  # 2. ソースコード抽出
  let code = extractRunnableExamplesSource(d.conf, n)

  # 3. 出力ディレクトリ準備
  let outputDir = d.exampleOutputDir
  createDir(outputDir)
  inc d.exampleCounter

  # 4. 例ファイル生成
  let outp = outputDir / RelativeFile("...")
  var code2 = """
{.line: $#.}:
$#
""" % [$toInstantiationInfo(d.conf, n.info), codeIndent]

  code2 = """
#[
$#
]#
import std/assertions
import $#
$#
""" % [comment, d.filename.quoted, code2]
  writeFile(outp.string, code2)

  # 5. 例グループに追加
  if rdoccmd notin d.exampleGroups:
    d.exampleGroups[rdoccmd] = ExampleGroup(...)
  d.exampleGroups[rdoccmd].code.add "import $1\n" % outp.string.quoted
```

```nim
# compiler/docgen.nim 579-612行目
proc runAllExamples(d: PDoc) =
  let outputDir = d.exampleOutputDir
  for _, group in d.exampleGroups:
    if group.docCmd == docCmdSkip: continue

    # 例ファイル生成
    let outp = outputDir / RelativeFile("$1_group$2_examples.nim" % [...])
    writeFile(outp, group.code)

    # コンパイル・実行コマンド構築
    let cmd = "$nim $backend -r --lib:$libpath ... $file" % [...]

    # 実行
    if os.execShellCmd(cmd) != 0:
      d.conf.quitOrRaise "[runnableExamples] failed: ..."
```


## 5. インターフェース設計

### 5.1 公開API

| API | 説明 |
|-----|------|
| `newDocumentor` | ドキュメンテータの初期化 |
| `generateDoc` | ASTからドキュメント生成 |
| `finishGenerateDoc` | RST Pass 2実行 |
| `writeOutput` | HTML/LaTeX出力 |
| `writeOutputJson` | JSON出力 |
| `generateIndex` | インデックスファイル生成 |
| `commandDoc` | docコマンド実装 |
| `commandRst2Html` | rst2htmlコマンド実装 |
| `commandRst2TeX` | rst2texコマンド実装 |
| `commandJson` | jsondocコマンド実装 |

### 5.2 コマンドラインオプション

| オプション | 説明 |
|------------|------|
| `--project` | プロジェクト全体のドキュメント生成 |
| `--index:on/off` | インデックス生成の有無 |
| `--docCmd:cmd` | runnableExamples実行コマンド |
| `--docRoot:path` | ドキュメントルート |
| `--git.url:url` | ソースコードへのリンク用GitURL |


## 6. 出力形式

### 6.1 HTML出力
- テンプレート: `config/nimdoc.cfg`内の`doc.file`
- CSS: `doc/nimdoc.css`
- JavaScript: `doc/dochack.js`

### 6.2 LaTeX出力
- クラスファイル: `doc/nimdoc.cls`
- テンプレート: `doc.file`のLaTeX版

### 6.3 JSON出力
```json
{
  "orig": "filename.nim",
  "nimble": "package_name",
  "moduleDescription": "...",
  "entries": [
    {
      "name": "procName",
      "type": "skProc",
      "line": 10,
      "col": 0,
      "description": "...",
      "code": "proc procName*(...)"
    }
  ]
}
```


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

### 7.1 推奨読解順序

1. **データ構造の理解**
   - `compiler/docgen.nim` 39-111行目 - 主要型定義（TDocumentor、Item等）

2. **初期化処理**
   - `compiler/docgen.nim` 324-421行目 - newDocumentor関数

3. **コメント解析**
   - `compiler/docgen.nim` 434-471行目 - genComment、genRecComment

4. **シンボル処理**
   - `compiler/docgen.nim` 1048-1166行目 - genItem関数

5. **メイン生成ループ**
   - `compiler/docgen.nim` 1372-1431行目 - generateDoc関数

6. **Pass 2処理**
   - `compiler/docgen.nim` 1460-1571行目 - finishGenerateDoc関数

7. **出力処理**
   - `compiler/docgen.nim` 1785-1838行目 - writeOutput、writeOutputJson

### 7.2 プログラム呼び出し階層図
```
commandDoc
  |
  +-- parseFile (AST取得)
  |
  +-- newDocumentor
  |     |
  |     +-- newRstSharedState
  |     +-- initRstGenerator
  |
  +-- generateDoc
  |     |
  |     +-- genComment
  |     +-- genItem
  |     |     |
  |     |     +-- getAllRunnableExamples
  |     |     +-- nodeToHighlightedHtml
  |     |     +-- setIndexTerm
  |     |
  |     +-- traceDeps
  |     +-- exportSym
  |
  +-- finishGenerateDoc
  |     |
  |     +-- preparePass2
  |     +-- resolveSubs
  |     +-- renderRstToOut
  |     +-- completePass2
  |
  +-- writeOutput
  |     |
  |     +-- runAllExamples
  |     +-- genOutFile
  |
  +-- generateIndex
        |
        +-- writeIndexFile
```

### 7.3 データフロー図
```
                 Nim Source (.nim)
                        |
                        v
                +----------------+
                |   parseFile   |
                +-------+--------+
                        |
                        v
                +----------------+
                |     PNode     |
                |    (AST)      |
                +-------+--------+
                        |
        +---------------+---------------+
        |               |               |
        v               v               v
+-------------+  +-------------+  +-------------+
| nkProcDef   |  | nkTypeDef   |  |nkCommentStmt|
+------+------+  +------+------+  +------+------+
       |                |                |
       v                v                v
+-------------+  +-------------+  +-------------+
|  genItem    |  |  genItem    |  | genComment  |
+------+------+  +------+------+  +------+------+
       |                |                |
       +----------------+----------------+
                        |
                        v
                +----------------+
                | ModSections   |
                | (secItems)    |
                +-------+--------+
                        |
                        v
                +----------------+
                |finishGenerate |
                |    Doc        |
                +-------+--------+
                        |
                        v
                +----------------+
                | resolveSubs   |
                | renderRstToOut|
                +-------+--------+
                        |
                        v
                +----------------+
                |  writeOutput  |
                +-------+--------+
                        |
                        v
                  Output Files
             (.html/.tex/.json/.idx)
```

### 7.4 関連ファイル一覧

| ファイル | 役割 | 行数目安 |
|----------|------|----------|
| compiler/docgen.nim | ドキュメント生成メイン | 1970行 |
| compiler/docgen2.nim | セマンティック解析付き版 | - |
| packages/docutils/rst.nim | RST解析 | - |
| packages/docutils/rstgen.nim | RST→HTML/LaTeX変換 | - |
| packages/docutils/rstast.nim | RST AST定義 | - |
| packages/docutils/rstidx.nim | インデックス管理 | - |
| packages/docutils/dochelpers.nim | ドキュメントヘルパー | - |
| doc/nimdoc.cfg | HTMLテンプレート設定 | - |
| doc/nimdoc.css | ドキュメントスタイルシート | - |


## 8. 設計上の考慮点

### 8.1 RST 2パス処理
RST/Markdownの解析は2パスで行われる：
1. **Pass 1**: 構文解析とAST構築（parseRst）
2. **Pass 2**: クロスリファレンス解決とレンダリング（resolveSubs、renderRstToOut）

これにより、前方参照や他モジュールへのリンクが正しく解決される。

### 8.2 オーバーロードグループ
同名のプロシージャ（オーバーロード）は自動的にグループ化され、TOCとドキュメント内で一つのエントリとして表示される。アンカー名は`{名前}-procs-all`形式。

### 8.3 runnableExamples
コード例は実際にコンパイル・実行され、正しいことが検証される。`--doccmd:skip`で実行をスキップ可能。

### 8.4 インデックス生成
`--index:on`で`.idx`ファイルが生成され、`theindex.html`として統合される。これによりプロジェクト全体の検索が可能になる。
