A relative link in a README was resolved by the browser against the URL the
README happened to be rendered at, not against the file that contains it. On
/r/<repo> the link docs/getting-started.md became
/r/<repo>/docs/getting-started.md, and on /r/<repo>/code it became
/r/<repo>/docs/getting-started.md from a different base. Both 404. Images
broke the same way.
The fix gives a document that lives in the tree its own path, and rewrites the links and images in it after parsing and before rendering:
| In a README | Now resolves to |
|---|---|
docs/getting-started.md |
/r/<repo>/blob/main/docs/getting-started.md?preview=1 |
LICENSE |
/r/<repo>/blob/main/LICENSE |
img/shot.png (image) |
/r/<repo>/raw/main/img/shot.png |
docs/ |
/r/<repo>/tree/main/docs |
../LICENSE from docs/ |
/r/<repo>/blob/main/LICENSE |
Left alone, because they already name somewhere: a scheme (https:,
mailto:), //host, a site-absolute /path, and a bare #anchor or
?query that refers to the document itself. Also left alone: content with no
place in a tree — issue bodies, comments and release notes keep their relative
links exactly as authored.
How
The rewrite walks the goldmark AST rather than the markdown text, so
reference-style links and images are covered by the same rule, and a link
inside a code fence is never touched because it is not a link node. The source
view still shows the file’s bytes; only the rendered preview and the README
that the overview and code page display are rewritten. .. is clamped at the
repository root instead of walking out of it.
Tests
server/web/markdown_test.go—docHreftable test covering every rule, including directories, parent traversal, refs with a slash, and the destinations that must not be rewritten.server/web_test.go— pushes a README plus a document in a subdirectory and asserts the resolved links on the overview page, on the code page, and on the subdirectory document’s own preview; asserts the source view is unchanged.
Not in this change
Heading anchors. docs/architecture.md#using-vole-as-a-library now opens the
right file, and the fragment is preserved in the URL, but the document is
rendered without heading ids, so it does not scroll to the section. Adding
them is a separate decision about generated ids on every rendered document
(issues and comments included), where a heading named main would collide
with the page’s <main id="main">. Worth its own issue rather than a rider
on this one.
Closes #01M5XF52R132A88C6WEQ6H6BK6