FuguWeb

App::FuguWeb::Check(3p) Perl Library Manual App::FuguWeb::Check(3p)

App::FuguWeb::Check - what a built site must be true of

    use App::FuguWeb::Check;
    my $check = App::FuguWeb::Check->new(
        config => $config,
        out    => 'web/build',
    );
    my @problems = $check->run;
    warn "$_\n" for @problems;
    note("external link: $_") for $check->external;

The checks are generic, so every project that uses the tool gets them. A project keeps only the assertions that are about its own content.

The class never fetches a link. It collects the external ones and reports them, because the build and its checks touch no network.

    App::FuguWeb::Check->new(
        config => $config,      # required
        out    => $dir,         # required: the built site
    )

"pages" names each page of each language tree, as "<code>/<page>": for each language, the pages of the description, then one page for each manual of each group. "generated_pages" names the human page of each key directory, which the build writes itself and which no block names. The pages of the top level sit outside every tree as well, and "top_pages" in App::FuguWeb::Config names them.

A generated page takes the checks of a page. It takes no reachability check: a site links the key directory when it chooses to. The pages of the top level take none either.

The full expectation, assets and the pages of the top level included, comes from "inventory" in App::FuguWeb::Config, so the build and the checks can never disagree about what the site is.

Check the site and return the problems, each one a sentence that names the page. An empty list means the site is good.

The checks are:

  • every expected page and asset exists and is not empty;
  • on every page but the top-level index.html, the check finds a title, the header link and every navigation link;
  • each of those links takes the form of the kind of its page: "<page>" on a tree page, "../en/<page>" on the key page, and "en/<page>" on the top-level copy of 404.html. An absolute URL and a fragment stay as they stand;
  • every page of a language tree carries the code of its tree as "lang";
  • the chrome of a tree page links the same page in each other language, as "<a href="../<code>/<page>" hreflang="<code>"><code></a>". The chrome of any other page, and of a site of one language, holds no "hreflang". The chrome ends where the "<main>" element starts, so a link of the body is the writer's own;
  • no reference starts with "/", because the host may serve the site from a path below the root. The "<base href="/">" of the top-level copy of 404.html is the one exception, and that page must carry it;
  • the top-level index.html holds a meta refresh to the entry page of the default tree. Its one reference is a link to that page, so it loads nothing, and it carries no navigation;
  • no reference uses a "file:" URL;
  • every relative reference resolves to a file in the output, a manual cross-reference included;
  • a reference of a page resolves against the directory of that page: a language tree, a key directory, or the top level;
  • every fragment resolves to an "id" on the target page;
  • no relative href reads as a URL scheme, so every local link keeps its "./";
  • every page of a language tree is reachable from the entry page of that tree, except a page that the description marks "unlinked". The walk stays inside the tree;
  • the output holds the site and nothing else, at any depth: no staging directory, no editor backup, no stray source, and no empty directory.

A description with a "keys" block adds the checks of "THE CHECKS" in App::FuguWeb::Keys. They read the source key directory and not the output. A stray key file and a stale digest are therefore found whether or not a build has run.

The external links that the last "run" collected, sorted.

App::FuguWeb, App::FuguWeb::Config, App::FuguWeb::Keys, App::FuguWeb::Site, fuguweb(1)

Dick Olsson <hi@senzilla.io>

2026-10-21 OpenBSD