docanvil 0.1.8

A Rust-based static documentation generator that converts Markdown into HTML sites
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

DocAnvil is a Rust-based static documentation generator that converts Markdown into HTML sites. It features live reloading, custom components, configurable styling, and static output for deployment anywhere.

## Build Commands

```bash
cargo build                    # Debug build
cargo build --release          # Release build
cargo test                     # Run all tests
cargo test <test_name>         # Run a single test
cargo clippy                   # Lint
cargo fmt                      # Format code
cargo install --path .         # Install locally
```

## CLI Interface

The binary exposes three subcommands:

- `docanvil init <name>` — scaffold a new documentation project
- `docanvil serve [--host <addr>] [--port <port>]` — dev server with hot reload (defaults: 127.0.0.1:3000)
- `docanvil build [--out <path>] [--clean]` — generate static HTML site (default output: `dist/`)

Global flags: `--verbose`, `--quiet`

## Architecture

### Module Structure

```
src/
  main.rs                    # clap CLI dispatch
  cli/
    mod.rs                   # Cli struct (clap derive), Command enum
    init.rs                  # docanvil init — scaffolds project directory
    serve.rs                 # docanvil serve — starts tokio runtime + server
    build.rs                 # docanvil build — orchestrates full build pipeline
  config.rs                  # docanvil.toml parsing (serde + toml)
  project.rs                 # PageInventory, NavNode, file discovery
  error.rs                   # thiserror Error enum
  diagnostics.rs             # colored warnings (owo-colors)
  pipeline/
    mod.rs                   # process() — full pipeline: directives → markdown → wikilinks → attributes
    markdown.rs              # comrak rendering with GFM extensions
    wikilinks.rs             # [[link]] and [[link|text]] resolution against PageInventory
    directives.rs            # :::directive{attrs} pre-comrak pass (regex + stack-based)
    attributes.rs            # {.class #id} post-comrak injection
  components/
    mod.rs                   # Component trait, ComponentRegistry, ComponentContext
    builtin/
      mod.rs, note.rs, warning.rs, tabs.rs, code_group.rs
  theme/
    mod.rs                   # Theme resolution (rust-embed + user overrides)
    default/
      style.css              # CSS-variable-based default theme
      layout.html            # Tera template with {% block %} sections
  render/
    mod.rs
    templates.rs             # Tera engine wrapper, PageContext struct
    assets.rs                # Static asset + custom CSS copying
  server/
    mod.rs                   # axum router setup, server start
    watcher.rs               # notify file watcher with debounce
    websocket.rs             # WebSocket handler for live reload
```

### Pipeline Flow

```
Markdown source
  → directives.rs    (pre-comrak: :::name{attrs} → component HTML)
  → markdown.rs      (comrak: Markdown → HTML with GFM extensions)
  → wikilinks.rs     (resolve [[links]] against PageInventory)
  → attributes.rs    (inject {.class #id} into preceding HTML tags)
  → templates.rs     (Tera: wrap in layout with nav, CSS, scripts)
  → output file
```

### Key Design Decisions

- **Parser**: comrak with GFM extensions (tables, task lists, strikethrough, footnotes, front matter)
- **Wiki-links**: `[[page-name]]` / `[[page-name|display text]]` resolved against slug inventory
- **Components**: Fenced directives (`:::name{key="val"}`) parsed pre-comrak; inline attributes (`{.class}`) post-comrak
- **Component trait**: `name()` + `render(ctx) -> Result<String>`; registry maps names to `Box<dyn Component>`
- **Styling**: Layered — embedded CSS-variable theme + config overrides + user template overrides (Tera)
- **Templates**: Tera with `{% block %}` sections; embedded defaults via rust-embed, user overrides in `theme/templates/`
- **Server**: axum with tokio; broadcast channel connects file watcher → WebSocket → browser reload
- **Config**: `docanvil.toml` with `[project]`, `[build]`, `[theme]` sections; serde deserialization

### Dependencies

Core: `clap` (CLI), `comrak` (Markdown), `serde`/`toml` (config), `thiserror` (errors), `walkdir` (file discovery), `regex` (directive parsing)

Rendering: `tera` (templates), `rust-embed` (embedded assets)

Server: `axum` (HTTP + WebSocket), `tokio` (async runtime), `tower-http` (static file serving), `notify`/`notify-debouncer-mini` (file watching)

Polish: `miette` (diagnostics), `owo-colors` (colored output)