aboutsummaryrefslogtreecommitdiffstats
path: root/README.md
blob: c670e6cd0039277e9e3d8dd7a76745bd8ea0be4d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
# ziglang-docs-epub

Turns the [Zig language reference](https://ziglang.org/documentation/) into an
**EPUB**, one per Zig version. CI runs it on a schedule and commits the resulting
`.epub` files back into [`epubs/`](https://git.simenandre.no/ziglang-docs-epub/tree/epubs).

## Why

The reference ships as a single self-contained HTML page. This tool repackages it
as a standards-compliant EPUB3 so you can read it offline in any e-reader.

## How it works

Four decoupled concerns, each a small module that does one thing:

| Module        | Responsibility                                            |
| ------------- | --------------------------------------------------------- |
| `index.zig`   | discover versions + docs URLs from `download/index.json`  |
| `fetch.zig`   | HTTP GET via `std.http.Client`                            |
| `html.zig`    | HTML5 → XHTML5; extract the in-page TOC; drop the sidebar |
| `epub.zig`    | assemble the EPUB3 container (TOC navigation + content)   |
| `zip.zig`     | minimal, reproducible ZIP writer (stored entries)         |

No external runtime dependencies — Zig's standard library provides HTTP and
CRC32. EPUB entries are stored uncompressed (Zig 0.15.2's std deflate
*compressor* is unfinished), which keeps the writer trivial and fully
spec-compliant at the cost of larger files. Output is **byte-for-byte
reproducible** (fixed ZIP timestamps), so CI only commits when the upstream docs
actually change.

### Table of contents

The docs page renders its table of contents in a `position: fixed` sidebar, which
e-readers repaint on every page. The tool extracts that TOC into a proper EPUB3
navigation document (`nav.xhtml`): it shows in the reader's built-in Contents
menu, is the book's opening page, and each entry jumps to the matching section.
The original fixed sidebar (and its dead version-switcher dropdown) is removed
from the content so it no longer bleeds across pages.

### Well-formedness gate

Each transformed page is checked for well-formed, balanced XHTML before
packaging; versions that fail are **skipped** (logged as `NotWellFormed`) rather
than shipped as invalid EPUB3. A handful of older docs pages (currently 0.1.1–0.8.1
and 0.10.x) contain malformed upstream HTML — unclosed `<p>`/`<li>` tags and
outright typos — that can't be repaired without a full HTML5 tree-builder. Every
EPUB this tool produces is therefore strictly well-formed; newer versions are
picked up automatically as they are released.

## Usage

Requires **Zig 0.15.2**.

```sh
zig build run            # build every version that has docs
zig build run -- 0.15.2  # build only specific version(s)
zig build test           # run unit tests
```

EPUBs land in `epubs/zig-<version>.epub`.

### Validating output

The tool guarantees well-formed XHTML, but full EPUB3 conformance (the kind of
thing Kindle's "Send to Kindle" enforces) is checked with
[epubcheck](https://github.com/w3c/epubcheck), the official validator:

```sh
brew install epubcheck   # one-time (needs a JRE)
./validate.sh            # runs epubcheck on every epub; non-zero exit on errors
```

`validate.sh` fails loudly if any EPUB has errors, so it doubles as a CI gate.

## Continuous integration

`.forgejo/workflows/build-epubs.yml` runs on [Codeberg](https://codeberg.org)
(Forgejo Actions): daily, on push to `main`, and on manual dispatch. It installs
Zig, runs the tool, and commits any changed EPUBs with `[skip ci]`.

## License

Licensed under the [Apache License 2.0](LICENSE).