mirror of
https://git.anardil.net/austin/verify-links.git
synced 2026-10-24 15:52:07 +00:00
Verify links in static web resources
- Haskell 97.6%
- HTML 2%
- Makefile 0.4%
Trim C0 controls and space from a link's ends and remove tab, LF and CR inside it, as the URL parser does, instead of T.strip. An NBSP or other Unicode space is now part of the link, and --allow values are read the same way, so an allow is written as its failure prints. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|---|---|---|
| Links | ||
| src | ||
| test | ||
| .gitignore | ||
| .hlint.yaml | ||
| CLAUDE.md | ||
| hie.yaml | ||
| LICENSE | ||
| Makefile | ||
| README.md | ||
| stack.yaml | ||
| stack.yaml.lock | ||
| verify-links.cabal | ||
verify-links
Checks a built static site's links: every href, src, srcset and poster
in every page, against the files in the tree, offline. With --remote it also
probes the site's links to anardil.net and its subdomains, live.
verify-links [--site HOST] [--html-ext] [--remote] [--allow LINK]... DIR
- A link to
/x/passes whenx/index.htmlexists, and a link to/xwhenxorx/index.htmldoes.--html-extalso acceptsx.html, for sites whose nginx block has the@htmlextfallback. --site HOSTcheckshttps://HOST/...links in the tree as well.- A tag written inside a style, title or textarea is read as markup, and its
link checked: a false failure rather than a missed link. Script text is not
read as markup. A
<!--there with no-->hides the links after it. - A link is read as a browser reads it: control characters and spaces at its ends are dropped, and tabs and newlines inside it removed. Any other space, NBSP included, is part of the link.
- Links are looked up by their exact case, as the server does, even on a case-insensitive filesystem. A symlinked directory is not followed, so a link into one is reported missing.
- Any
http://link fails, and so does one that climbs above the root or won't parse. Other people's sites,mailto:and the like are not checked. --remoteasks for each https URL on anardil.net or a subdomain (other than--site) as written, through the system resolver and no proxy, and a 2xx passes. A redirect is not followed: it fails, and says where it goes, ashttp 301 LINK -> TARGETwith the Location resolved against LINK.- A page behind a login passes, and the summary counts it
behind a login: a 401, or a redirect to the same scheme, host and port that carries the link's path (with or without its query) or the whole link as a query value, under any parameter name, or that comes from the site's root. So/dashboards -> /login?redirectTo=%2Fdashboardsand/ -> /loginpass, and/blog -> /blog/oranardil.net -> www.anardil.netfail. A name that doesn't resolve, which is what a LAN-only host looks like off the LAN, is reported asunresolved. Each request has a 10 second timeout to connect and answer, though a DNS lookup that stalls can take longer before it is reported. --allow LINKaccepts a link known to be fine: one that fails, written as the failure prints it, on any page, for any reason. LINK is read as a link on a page is. The link is checked as usual, and probed with--remote, so an allow that allowed nothing gets a note on stderr:no page links to it,it isn't checked(another site,mailto:and the like) orit passes. The note doesn't change the exit code. An allow for a remote link that wasn't probed gets no note: it might yet fail.
Failures go to stdout, one per page and link (page: kind link), and a summary
to stderr, which counts the failures allowed. Exit 0 when clean, 1 for any
failure not allowed, 2 when the tree can't be checked: no such directory, no
pages, an unreadable tree, no http client for --remote, or bad arguments.
make release # installs ~/.local/bin/verify-links
make ready # format, lint, test