From 0806fecb47f5a2a26e73ca8b6e28c08f9945ef75 Mon Sep 17 00:00:00 2001 From: "Simen A. W. Olsen" Date: Fri, 29 May 2026 00:06:48 +0200 Subject: fix problems after testing with epubcheck --- epubs/zig-0.11.0.epub | Bin 1083315 -> 1086285 bytes epubs/zig-0.12.0.epub | Bin 925023 -> 928020 bytes epubs/zig-0.12.1.epub | Bin 935649 -> 938646 bytes epubs/zig-0.13.0.epub | Bin 935698 -> 938695 bytes epubs/zig-0.14.0.epub | Bin 966701 -> 969788 bytes epubs/zig-0.14.1.epub | Bin 970004 -> 973091 bytes epubs/zig-0.15.1.epub | Bin 973287 -> 976374 bytes epubs/zig-0.15.2.epub | Bin 972519 -> 975597 bytes epubs/zig-0.16.0.epub | Bin 986269 -> 989455 bytes epubs/zig-0.9.0.epub | Bin 1115228 -> 1118090 bytes epubs/zig-0.9.1.epub | Bin 1115381 -> 1118252 bytes epubs/zig-master.epub | Bin 969372 -> 972486 bytes src/html.zig | 13 +++++++++++-- validate.sh | 32 ++++++++++++++++++++++++++++++++ 14 files changed, 43 insertions(+), 2 deletions(-) create mode 100755 validate.sh diff --git a/epubs/zig-0.11.0.epub b/epubs/zig-0.11.0.epub index 1dfc0f0..8751a77 100644 Binary files a/epubs/zig-0.11.0.epub and b/epubs/zig-0.11.0.epub differ diff --git a/epubs/zig-0.12.0.epub b/epubs/zig-0.12.0.epub index 05bb36e..9dca6f3 100644 Binary files a/epubs/zig-0.12.0.epub and b/epubs/zig-0.12.0.epub differ diff --git a/epubs/zig-0.12.1.epub b/epubs/zig-0.12.1.epub index 1907d2f..64b2179 100644 Binary files a/epubs/zig-0.12.1.epub and b/epubs/zig-0.12.1.epub differ diff --git a/epubs/zig-0.13.0.epub b/epubs/zig-0.13.0.epub index 98cce35..f242a27 100644 Binary files a/epubs/zig-0.13.0.epub and b/epubs/zig-0.13.0.epub differ diff --git a/epubs/zig-0.14.0.epub b/epubs/zig-0.14.0.epub index 39d7ea3..1af8ecd 100644 Binary files a/epubs/zig-0.14.0.epub and b/epubs/zig-0.14.0.epub differ diff --git a/epubs/zig-0.14.1.epub b/epubs/zig-0.14.1.epub index 1f14838..378dbb1 100644 Binary files a/epubs/zig-0.14.1.epub and b/epubs/zig-0.14.1.epub differ diff --git a/epubs/zig-0.15.1.epub b/epubs/zig-0.15.1.epub index be73887..564ab1e 100644 Binary files a/epubs/zig-0.15.1.epub and b/epubs/zig-0.15.1.epub differ diff --git a/epubs/zig-0.15.2.epub b/epubs/zig-0.15.2.epub index f4845af..152f4e4 100644 Binary files a/epubs/zig-0.15.2.epub and b/epubs/zig-0.15.2.epub differ diff --git a/epubs/zig-0.16.0.epub b/epubs/zig-0.16.0.epub index 6490d41..114bee7 100644 Binary files a/epubs/zig-0.16.0.epub and b/epubs/zig-0.16.0.epub differ diff --git a/epubs/zig-0.9.0.epub b/epubs/zig-0.9.0.epub index 514d283..b6f6dd4 100644 Binary files a/epubs/zig-0.9.0.epub and b/epubs/zig-0.9.0.epub differ diff --git a/epubs/zig-0.9.1.epub b/epubs/zig-0.9.1.epub index 9914fdd..fbc087d 100644 Binary files a/epubs/zig-0.9.1.epub and b/epubs/zig-0.9.1.epub differ diff --git a/epubs/zig-master.epub b/epubs/zig-master.epub index 139d828..2dd2111 100644 Binary files a/epubs/zig-master.epub and b/epubs/zig-master.epub differ diff --git a/src/html.zig b/src/html.zig index ec9ecfd..fe7f287 100644 --- a/src/html.zig +++ b/src/html.zig @@ -63,10 +63,16 @@ pub fn transform(allocator: std.mem.Allocator, page: []const u8) !Document { const no_sidebar = try removeNavigation(allocator, escaped); defer allocator.free(no_sidebar); + // Section headings link back to their entry in the removed sidebar + // (`href="#toc-X"`); redirect those to the matching anchors now in nav.xhtml, + // otherwise they are dangling fragments (epubcheck RSC-012, breaks Kindle). + const relinked = try std.mem.replaceOwned(u8, allocator, no_sidebar, "href=\"#toc-", "href=\"nav.xhtml#toc-"); + defer allocator.free(relinked); + var out: std.Io.Writer.Allocating = .init(allocator); defer out.deinit(); try out.writer.writeAll(xml_decl); - try writeWithFixups(&out.writer, no_sidebar); + try writeWithFixups(&out.writer, relinked); const content = try out.toOwnedSlice(); assert(std.mem.startsWith(u8, content, "
  • Intro" ++ "
  • " ++ "" ++ - "

    Intro

    body

    " ++ + "

    Intro

    body

    " ++ ""; var doc = try transform(gpa, page); @@ -549,6 +555,9 @@ test "transform extracts TOC and removes the navigation sidebar" { try std.testing.expect(std.mem.indexOf(u8, doc.content, "
    ") != null); try std.testing.expect(std.mem.indexOf(u8, doc.content, "

    ") != null); try std.testing.expect(isWellFormed(doc.content)); + // Back-to-contents link is redirected to the nav document (no dangling fragment). + try std.testing.expect(std.mem.indexOf(u8, doc.content, "href=\"nav.xhtml#toc-Intro\"") != null); + try std.testing.expect(std.mem.indexOf(u8, doc.content, "href=\"#toc-Intro\"") == null); // TOC extracted, ul->ol, links rewritten into the content document. try std.testing.expect(doc.toc != null); diff --git a/validate.sh b/validate.sh new file mode 100755 index 0000000..f932f11 --- /dev/null +++ b/validate.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Validate every generated EPUB with epubcheck (the official EPUB validator). +# Exits non-zero if any EPUB has errors, so it can gate CI. +# +# Requires epubcheck on PATH (e.g. `brew install epubcheck`). + +set -uo pipefail + +if ! command -v epubcheck >/dev/null 2>&1; then + echo "error: epubcheck not found. Install it (e.g. 'brew install epubcheck')." >&2 + exit 127 +fi + +shopt -s nullglob +epubs=(epubs/*.epub) +if [ ${#epubs[@]} -eq 0 ]; then + echo "error: no EPUBs in epubs/. Run 'zig build run' first." >&2 + exit 1 +fi + +fail=0 +for f in "${epubs[@]}"; do + if epubcheck "$f" >/dev/null 2>&1; then + echo "PASS $f" + else + echo "FAIL $f" + epubcheck "$f" 2>&1 | grep -E '^(ERROR|FATAL|WARNING)' | sed 's/^/ /' + fail=1 + fi +done + +exit $fail -- cgit v1.2.3