Skip to main content

max / docengine

git clone https://makenot.work/git/max/docengine.git git clone git@ssh.makenot.work:max/docengine.git
Name Size
/ docs/
/ src/
· .gitignore 19 B
· Cargo.lock 30.1 KB
· Cargo.toml 752 B
· README.md 5.7 KB

README

DocEngine

Configurable markdown-to-HTML rendering library with sanitization presets. Built on pulldown-cmark (GFM) and ammonia.

Used by MNW (site docs, blog posts, user-generated content), Multithreaded (forum posts), and the desktop apps (descriptions, notes).

Presets

Four rendering presets, each with different security/feature tradeoffs:

PresetUse caseTablesImagesRaw HTMLDangerous scheme filterSanitization
PermissiveDocs, blog posts (trusted)YYYNDefault ammonia
StandardApp text fields (descriptions)YNYNDefault ammonia
StrictUser-generated content (forums)NNNYnofollow on links
Sanitize-onlyExternal HTML (RSS feeds)Default ammonia, no markdown parsing
use docengine::{render_permissive, render_standard, render_strict, sanitize_html};

// Convenience functions
let html = render_permissive("# Hello\n\n**Bold** text");
let html = render_standard("A description with [link](https://example.com)");
let html = render_strict("User post with @mentions and `code`");
let html = sanitize_html("<p>Pre-rendered</p><script>stripped</script>");

// Builder pattern for custom configurations
use docengine::{Renderer, SanitizePreset};

let html = Renderer::permissive()
    .with_strip_images(true)       // override: strip images even in permissive
    .with_footnotes(false)
    .render("# Custom config");

// Render with metadata (word count, reading time)
let result = Renderer::standard().render_with_meta("Some article text...");
println!("{} words, ~{} min read", result.word_count, result.reading_time_minutes);

Feature Flags

All optional features are off by default. Enable what you need:

FlagDependenciesProvides
doc-loaderregexDocLoader – load a directory of .md files into an in-memory page store
directivesregex-litepost_process_directives[!NOTE]/[!TIP]/[!TABS] blockquote alerts and code tabs
frontmattertomlparse_frontmatter – extract TOML frontmatter delimited by +++
mentionsregex-liteextract_mentions, resolve_mentions@username parsing and linking
quotesregex-lite, uuidpost_process_quotes – replace [quote:POST_ID:HASH] markers with author attribution
media-urlsregex-literewrite_media_paths, img_to_video – CDN path rewriting and video tag conversion
fullall of the aboveEnable everything
# In Cargo.toml
docengine = { path = "../Shared/docengine" }                    # Core only
docengine = { path = "../Shared/docengine", features = ["full"] } # Everything

Core API

Types

  • Renderer – configurable markdown renderer with builder pattern
  • RenderResult – rendered HTML plus word_count and reading_time_minutes
  • SanitizePresetPermissive, Standard, Strict, Minimal
  • TocEntry – heading level, text, and anchor for table of contents

Functions

FunctionDescription
render_permissive(md)Render with full GFM features
render_standard(md)Render without images
render_strict(md)Render with all restrictions (UGC-safe)
sanitize_html(html)Clean pre-rendered HTML without markdown parsing
word_count(text)Count words in raw text
reading_time_minutes(wc)Estimate reading time (200 wpm)
extract_title(md)Pull the first # Heading from markdown
strip_first_heading(md)Remove the first # Heading (for template-rendered titles)
extract_toc(md)Build a Vec<TocEntry> from all headings
render_toc_html(entries)Render TOC entries as a <nav class="toc"> HTML list

Feature-gated

Function / TypeFeatureDescription
DocLoader::load(path, config)doc-loaderLoad .md files from disk, render to HTML, build searchable index
DocPage, DocIndexEntrydoc-loaderPage and index entry types
post_process_directives(html)directivesConvert [!NOTE]/[!TIP]/etc. blockquotes to alert divs, [!TABS] to tabbed code blocks
parse_frontmatter(input)frontmatterParse +++-delimited TOML frontmatter
FrontmatterfrontmatterStruct with title, date, tags, section, draft, extra
extract_mentions(md)mentionsFind unique @username mentions (skips code blocks)
resolve_mentions(md, valid, template)mentionsReplace @user with [@user](/path/to/user) for known usernames
post_process_quotes(html, authors)quotesReplace [quote:UUID:HASH] with clickable attribution
rewrite_media_paths(md, base, user)media-urlsRewrite relative image paths to absolute CDN URLs
img_to_video(html)media-urlsConvert <img> tags pointing to video files into <video> elements

Consumers

ProjectFeatures usedPreset
MNWdoc-loader, directives, frontmatter, media-urlsPermissive (docs/blog), Standard (descriptions)
Multithreadedmentions, quotesStrict (forum posts)
GoingsOncore onlyStandard (notes, descriptions)
Balanced Breakfastcore onlySanitize-only (RSS feed content)

Security

All presets sanitize output through ammonia. The strict preset additionally:

  • Strips all raw HTML and images at the parser level (before ammonia)
  • Replaces javascript:, data:, vbscript: URLs with #
  • Adds rel="noopener noreferrer nofollow" to all links

Zero unsafe code.

License

PolyForm Noncommercial 1.0.0