Checking links

How devpage finds broken links: what counts as a problem, how the preview shows problems while you write, and how devpage check fails a test or a CI job on them. It is a task article under the viewer.

What is checked

Every link a reader could follow and every file a page loads — Markdown links, images, links and src attributes in raw HTML, and the targets of Mermaid click lines:

What Must
A target inside the served folder exist, inside the served folder
A #fragment name a heading or id on the page it points at
#n on a deck be a slide the deck has
A document file be valid for its kind, with its root, chapters and slides naming existing files
A Topics entry point at an existing page
An http or https address answer with a status below 400, following redirects
A comment thread parse, for each file in the comment store
A design a page links to or embeds parse and resolve, with every design it imports — see Designs

An external answer of 400 or above is a broken link at once. An address that doesn't answer within 10 seconds, or can't be connected to, may only be a slow network, so it is asked again before it counts — see In the preview and devpage check for how. devpage asks for each one as a browser asks for a page, accepting HTML, since some sites answer other requests with an error no reader sees. Each address is asked once per check, however many links point at it.

mailto: and other schemes are not checked.

Links in a widget's content are checked like any other, since devpage renders that Markdown. Links a widget's own code builds in the browser are not: devpage never runs widget code on the server.

Designs

Every .design file a page links to or embeds, and every design those import, must parse and resolve: known elements, attributes and props, values of the right type, imports and images that exist in the served folder, and no design that uses itself (Designs). They are read from the page's Markdown — an image or a link whose target ends in .design, never an example in code — and each of the design's problems is reported on the page as broken design <target> — <file>:<line>:<column>: <message>. A design whose drawing is too big to paint is a problem too. A link to a design's PNG address, x.design.png, is checked as the design x.design (Looking at a design as a PNG).

In the preview

While devpage serves a document, each page lists its own problems in a bar at its top, and every broken link on it is marked where it stands — a red wavy underline on a link, a dashed outline on an image, a dashed red border on a diagram node. They update as you edit, like the rest of the page: fix the link, save, and the problem goes. devpage also prints each problem once on its terminal, as it first finds it:

$ devpage docs
devpage → http://localhost:3030
docs/boxes/viewer/README.md:42: broken link ../serving/README.md — no such file
docs/README.md:7: broken link design/devpage.yml — in docs/design/devpage.yml: chapter rollout.md does not exist
docs/README.md:9: broken link talk/devpage.yml#9 — the deck has 3 slides
docs/README.md:12: https://example.com/gone — 404 Not Found

Files are named by their path from the top of the served folder. A document file that can't be loaded is reported on the page that links to it.

External links are checked in the background, so a slow site never holds a page up. An address that answers 400 or above shows as a problem as soon as its answer arrives. One that doesn't answer within 10 seconds, or can't be connected to, is asked again after 30 seconds, then 60, then every 120 — and shows as a problem only after three failures in a row, as <address> — <why>, 3 times in a row. Once it answers, the problem goes. An address that has answered is not asked again for as long as devpage runs. Each change reaches open pages through the live-update stream, like a saved file.

devpage check

$ devpage check docs
docs/README.md:12: https://example.com/gone — 404 Not Found
$ echo $?
1

It takes a document file's folder (docs, for docs/devpage.yml), one Markdown file (devpage check design.md), or one design (devpage check app/checkout.design), whose problems it prints as <file>:<line>:<column>: <message>.

devpage check takes the same argument as devpage, checks that document and every page and document reachable from it by links within the served folder, prints every problem in the same file:line: problem form, and exits with 1 if there was any and 0 if there were none. An external address that doesn't answer within 10 seconds, or can't be connected to, is asked once more with 30 seconds to answer before it is reported; one that answers 400 or above is reported at once. It starts no server. Use it in a test or a CI job to keep the docs from shipping a broken link. devpage's own tests check devpage's docs the same way, external links aside, so the test suite needs no network.