# herolib-web

Fast, ergonomic web utilities for Markdown and HTML processing.

## Features

- **Markdown → HTML**: Convert with Bootstrap 5.3.8 styling built-in
- **HTML Utilities**: Parsing, validation, minification, escaping  
- **Builders**: Ergonomic APIs via builder pattern for both Markdown and HTML
- **Bootstrap Integration**: Automatic CSS/JS injection, removal, and updates

## Installation

```toml
[dependencies]
herolib-web = { path = "packages/web", version = "0.3.3" }
```

## Markdown: Basic Usage

```rust
use herolib_web::markdown;

// Complete HTML5 page (ready to save as .html file)
let html = markdown::markdown_to_html_page("# Hello\n\nWorld", "My Page");
std::fs::write("page.html", html)?;

// Embed in existing page
let fragment = markdown::markdown_to_html_bootstrap("# Title\nContent");
// Returns: <div class="container mt-5 mb-5">..HTML..</div>

// Extract headings & word count
let headings = markdown::extract_headings(md);
let words = markdown::count_words(md);
```

## Markdown: Builder Pattern

```rust
use herolib_web::markdown::MarkdownBuilder;

let md = MarkdownBuilder::new()
    .heading(1, "Guide")?
    .paragraph("Intro text")
    .heading(2, "Section")?
    .list(&["Item 1", "Item 2"])
    .code_block("rust", "fn main() {}")
    .ordered_list(&["Step 1", "Step 2"])
    .blockquote("A quote")
    .link("Site", "https://example.com")
    .build();

let html = markdown::markdown_to_html(&md);
```

## Markdown: Functions Reference

| Function | Returns | Purpose |
|----------|---------|---------|
| `markdown_to_html(md)` | `String` | Raw HTML conversion |
| `markdown_to_html_page(md, title)` | `String` | Standalone page (with Bootstrap) |
| `markdown_to_html_bootstrap(md)` | `String` | Container div for embedding |
| `markdown_to_toc_bootstrap(md)` | `String` | Table of contents nav |
| `extract_headings(md)` | `Vec<(usize, String)>` | (level, text) tuples |
| `count_words(md)` | `usize` | Word count |
| `count_lines(md)` | `usize` | Line count |
| `MarkdownBuilder` | Builder | Programmatic generation |

## HTML: Basic Usage

```rust
use herolib_web::html;

// XSS prevention
let safe = html::escape_html("<script>alert('xss')</script>");

// Remove HTML tags
let text = html::extract_text("<p>Keep <b>this</b></p>");

// Validate structure
html::validate_html("<div><p>OK</p></div>")?;

// Minify (remove whitespace)
let min = html::minify_html(html);
```

## HTML: Bootstrap Management

```rust
use herolib_web::html;

// Add Bootstrap 5.3.8 (removes old versions, idempotent)
let with_bs = html::add_bootstrap(html);

// Remove all Bootstrap references
let without = html::remove_bootstrap(&with_bs);
```

## HTML: Builder Pattern

```rust
use herolib_web::html::HtmlBuilder;

let page = HtmlBuilder::new()
    .add_tag("h1", "Title", &[])
    .add_tag("p", "Text", &[("class", "lead")])
    .add_tag("a", "Link", &[("href", "https://example.com")])
    .build();
```

## HTML: Functions Reference

| Function | Purpose |
|----------|---------|
| `escape_html(text)` | Encode special chars for safe HTML |
| `unescape_html(text)` | Decode HTML entities |
| `extract_text(html)` | Remove all tags |
| `minify_html(html)` | Remove whitespace |
| `validate_html(html)` | Check tag balance (returns `WebResult`) |
| `add_bootstrap(html)` | Inject Bootstrap 5.3.8 |
| `remove_bootstrap(html)` | Strip Bootstrap CDN links |
| `HtmlBuilder` | Build HTML programmatically |

## Real-World Examples

### Blog Post with TOC

```rust
use herolib_web::markdown;
use std::fs;

let md = fs::read_to_string("blog.md")?;
let toc = markdown::markdown_to_toc_bootstrap(&md);
let content = markdown::markdown_to_html_page(&md, "My Blog");

// Combine in your template
let page = format!("{}\n{}", toc, content);
fs::write("blog.html", page)?;
```

### File to HTML

```rust
use herolib_web::markdown;
use std::fs;

let content = fs::read_to_string("input.md")?;
let html = markdown::markdown_to_html_page(&content, "Title");
fs::write("output.html", html)?;
```

### HTML Cleaning

```rust
use herolib_web::html;

let dirty = "<p>  Content  </p>";
let clean = html::minify_html(dirty);      // "<p> Content </p>"

let text = html::extract_text(clean);      // "Content"
```

### Form Generation

```rust
use herolib_web::html::HtmlBuilder;

let form = HtmlBuilder::new()
    .add_tag("input", "", &[
        ("type", "email"),
        ("name", "email"),
        ("placeholder", "your@email.com")
    ])
    .add_tag("button", "Submit", &[("type", "submit")])
    .build();
```

## Error Handling

All fallible operations return `WebResult<T>`:

```rust
match markdown::MarkdownBuilder::new().heading(7, "Bad") {
    Ok(_) => {},
    Err(e) => println!("Error: {} (levels 1-6 only)", e),
}
```

Error variants: `HtmlParseError`, `MarkdownError`, `InvalidHtml`, `Utf8Error`, `IoError`, `JsonError`

## Bootstrap Details

- **Version**: Locked to 5.3.8 via CDN
- **CSS**: Added to `<head>` section
- **JS**: Added before `</body>` closing tag
- **Idempotent**: Safe to call `add_bootstrap()` multiple times
- **Smart**: Auto-detects missing head/body tags

## Performance

- **Regex cached** via `OnceLock` (zero overhead)
- **Zero-copy** markdown parsing (`pulldown-cmark`)
- **~40% size reduction** via `minify_html()`

## Testing & Docs

```bash
./build.sh    # Build, test, lint, generate docs
./run.sh      # Run demo app
cargo test    # Tests only
cargo doc --no-deps --open  # View API docs
```

## License

Apache-2.0
