Skip to content

v0.9.0 — the rewrite lands on crates.io

Latest

Choose a tag to compare

@thombruce thombruce released this 12 Jul 14:27

Identical to 0.6.0 apart from the version number. This is the first release of
the rewritten Sherwood published to crates.io: versions 0.6.0–0.8.0 were
already used by the pre-rewrite crate under the same name, and crates.io
version numbers are permanently reserved (yanked or not), so the rewrite skips
to 0.9.0. The pre-rewrite releases (old 0.1.0–0.8.0) are yanked.

Added

  • Pluggable content parsers. A ContentParser trait turns one file's raw source into a Parsed { frontmatter, content_html, excerpt_html } payload; a ParserRegistry maps file extensions to parsers (default() registers the built-in MarkdownParser for .md/.markdown; empty() starts bare; register(Arc::new(MyParser)) adds one, last registration for an extension wins). New public exports: ContentParser, Parsed, ParserError, ParserRegistry, MarkdownParser, markdown_to_html, split_frontmatter, plus the layered error types FrontmatterError and PageError.
  • Base-path support for subpath hosting (e.g. https://host/sherwood/). SiteConfig.base_path (via with_base_path or --base-path on build/serve, normalized to "" or "/prefix") prefixes generated URLs: NavItem.href, Breadcrumb.href, and prev/next hrefs come pre-resolved; PageContext::{base_path, resolve} cover hrefs templates build themselves. page.url and pages_under stay canonical (un-prefixed). Output paths are unaffected. The dev server mounts the site under the base path and redirects / to it, matching production.
  • Static-asset passthrough: files in the content tree whose extension has no registered parser (images, downloads, extra CSS, …) are now copied verbatim to the mirrored output path (content/blog/img.png_site/blog/img.png) instead of being silently dropped from the build.
  • Duplicate-output detection: two sources that map to the same output file (e.g. content/about.md and content/about/index.md, both → _site/about/index.html; or a static about/index.html colliding with a rendered page) now fail the build with BuildError::DuplicateOutput naming both sources, instead of one silently overwriting the other.
  • Dogfooding site: site/ is a publish = false workspace member that builds the project's documentation site (https://sherwood.thombruce.com) through the library/run_cli path with its own template and stylesheet, deployed to GitHub Pages on push to main. Excluded from the published crate.
  • CI now builds and tests the full feature matrix (default, no-default, cli-only, default-template-only) plus the site as a smoke test.
  • try_run_cli_from(args, registry, renderer, assets) — like try_run_cli but parses the given arguments (clap parse_from convention, first item is the binary name) instead of std::env::args, so tests and embedding binaries can drive the CLI directly.

Changed

  • Breaking: build_site gains a &ParserRegistry second parameter: build_site(&config, &registry, renderer, progress). Pass &ParserRegistry::default() for the previous markdown-only behaviour.
  • Breaking: run_cli / try_run_cli gain a ParserRegistry first parameter so binary authors can register custom parsers: run_cli(ParserRegistry::default(), renderer, assets).
  • Breaking: the module tree is now private behind a facade — lib.rs re-exports the public API and internal paths (sherwood::build::…, sherwood::page::…, etc.) are no longer reachable. In particular the serve module (router, router_with_reload, serve_with_watch) is no longer public; the supported serving entry point is the CLI's serve subcommand.
  • Breaking: SiteConfig is #[non_exhaustive]. Downstream crates construct via SiteConfig::new() / default() and the with_content_dir / with_output_dir / with_base_path builder methods instead of struct literals.
  • Breaking: error types are restructured per module. BuildError::FrontmatterParse { path, message } is gone; parse failures now arrive as BuildError::Page(PageError::Parse { path, source: ParserError }) with FrontmatterError at the bottom of the chain, and display transparently (path + line-numbered snippet, no stacked prefixes).
  • Breaking: parse_frontmatter(source, path) -> (FrontMatter, String, Option<String>) is replaced by split_frontmatter(source) -> Result<(FrontMatter, String), FrontmatterError>. Excerpt extraction (<!-- more -->) moved into MarkdownParser — it's a markdown concern, not a frontmatter one. Third-party parsers using the ---/+++ convention call split_frontmatter and handle excerpts themselves.
  • The build walks every file and dispatches by extension through the registry, instead of hardcoding .md; .markdown files are now recognized.
  • Breaking (behaviour): prev/next links are now scoped to the page's section instead of walking the full site-wide build order. Pages chain among siblings sharing the same URL parent — a blog post's neighbours are other posts under /blog/, never an unrelated page that happened to sort adjacent. Section indexes (/blog/) and top-level pages chain together in the root sequence. Sites relying on the old continuous site-wide chain will see prev/next end at section boundaries.

Fixed

  • sherwood serve now watches --asset override source files: editing e.g. a custom stylesheet triggers a rebuild and live reload, like content edits. Override bytes are also re-read from disk on every rebuild — previously they were read once at startup, so rebuilds rewrote stale bytes.

Removed

  • The root demo content/ directory. The bare cargo run -- build / serve now need a content/ dir to exist; use --content-dir or the site/ workspace member for a runnable example.

Tests

  • Test count: 79 → 118 (including 2 doctests).