pagez

Checking a site, and its rules

check lists every page's failure and every warning, a line each, with its id, and writes nothing. printedRule prints a rule, an error or a warning from the docs the package ships.

import { cpSync, existsSync, mkdtempSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { describe, expect, test } from "vite-plus/test";
import { check } from "../src/check.ts";
import { printedRule } from "../src/rules.ts";

/** A copy of a test site, to check in a folder of its own. */
function folder(name: string, from = "sites"): string {
  const dir = mkdtempSync(join(tmpdir(), "pagez-check-"));
  cpSync(new URL(`${from}/${name}/`, import.meta.url), dir, { recursive: true });
  return dir;
}

describe("check", () => {
  test("checks every page a build would, and writes no dist/", async () => {
    const root = folder("blog");
    expect(await check(root, root)).toEqual({ pages: 5, failures: [], warnings: [] });
    expect(existsSync(join(root, "dist"))).toBe(false);
  });

  test("lists each page's failure, where a build stops at its first, and each warning", async () => {
    const root = folder("folders");
    writeFileSync(join(root, "about.md"), "# About\n\n[Gone](gone.md)\n");
    writeFileSync(join(root, "notes.md"), "# Notes\n\nAt https://example.com/ and ${page.nope}.\n");
    const { failures, warnings } = await check(root, root);
    expect(failures).toEqual([
      expect.stringMatching(/^about\.md: line 3: .* \[error-link-missing\]$/),
      expect.stringMatching(/^notes\.md: line 3[,:] .* \[error-expression-missing\]$/),
    ]);
    expect(warnings).toEqual([]);
    writeFileSync(join(root, "notes.md"), "# Notes\n\nAt https://example.com/.\n");
    expect((await check(root, root)).warnings).toEqual([
      expect.stringMatching(/^notes\.md: line 3: bare URL\. .* \[bare-url\]$/),
    ]);
  });

  test("gives a mistake the site's pages share as its one line", async () => {
    const root = folder("error-site-url");
    expect(await check(root, root)).toEqual({
      failures: [expect.stringMatching(/^pagez\.md: .* \[error-site-url\]$/)],
      warnings: [],
    });
  });
});

describe("printedRule", () => {
  test("prints a rule, an error or a warning with its rule, and a Markz code", () => {
    expect(printedRule("folder-page")).toMatch(
      /^folder-page: A page is a `\.md`, at its folder's path\./,
    );
    expect(printedRule("error-link-missing")).toMatch(
      /^error-link-missing: Fails when .*\.\n\nlinks-checked: A link must reach a page/,
    );
    expect(printedRule("undefined-tag")).toMatch(
      /^undefined-tag: Warns when .*\n\nuse-undefined: /,
    );
    expect(printedRule("bare-url")).toMatch(/^bare-url: Markz warns at bare URL\. Instead: /);
    expect(printedRule("element-setup")).toMatch(/^element-setup: /);
  });

  test("prints every rule with no id, and nothing for an id that names none", () => {
    const all = printedRule()!.split("\n");
    expect(all).toContain(printedRule("folder-page"));
    expect(all.every((line) => /^[a-z][a-z0-9-]*: \S/.test(line))).toBe(true);
    expect(printedRule("nope")).toBeUndefined();
    expect(printedRule("toString")).toBeUndefined();
  });
});