@mark1russell7/site-pages 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as runCli } from "./build-CD2wc7Yl.js";
2
+ import { a as runCli, o as TYPESCRIPT_PROBE, s as probeScript } from "./build-xJqNIzdO.js";
3
3
  import { spawn } from "node:child_process";
4
4
  import { appendFileSync, createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
5
5
  import { delimiter, extname, isAbsolute, join, normalize, resolve, sep } from "node:path";
@@ -367,7 +367,8 @@ async function serve(root, base) {
367
367
  *
368
368
  * A view fails when the page is wider than the screen or an element goes past the right edge. It
369
369
  * also fails when a text area hides its text or the page shows no text. A console error, an
370
- * exception, a failed request of the site and a failed check of the probe also fail it. The command
370
+ * exception and a failed request of the site also fail it. A script that does not load and a failed check of the probe
371
+ * fail it too. The command
371
372
  * writes a screenshot of each view.
372
373
  */
373
374
  /** This function gives the file name part of a page: `/` is `home`, `/releases/` is `releases`. */
@@ -400,6 +401,7 @@ async function checkSite(options) {
400
401
  page.send("Runtime.enable"),
401
402
  page.send("Network.enable")
402
403
  ]);
404
+ await page.send("Page.addScriptToEvaluateOnNewDocument", { source: LOAD_WATCH });
403
405
  if (options.shots) mkdirSync(options.shots, { recursive: true });
404
406
  for (const [index, path] of options.pages.entries()) {
405
407
  const target = new URL(path.replace(/^\/+/, ""), homeUrl).href;
@@ -432,6 +434,16 @@ async function checkSite(options) {
432
434
  }
433
435
  return result;
434
436
  }
437
+ /**
438
+ * A script that each page starts before its own scripts. A script or a style sheet that does not load fires `error` on its
439
+ * element. This script writes that event as a console error. Thus a module script whose imports do not load is a problem too.
440
+ * Such a script throws no exception. Its failed request can go to another origin, for example `node:perf_hooks` in a page bundle.
441
+ */
442
+ const LOAD_WATCH = `addEventListener("error", (event) => {
443
+ const element = event.target;
444
+ if (!(element instanceof HTMLScriptElement || element instanceof HTMLLinkElement)) return;
445
+ console.error("failed to load " + element.tagName.toLowerCase() + ": " + (element.getAttribute("src") ?? element.getAttribute("href") ?? "(inline)"));
446
+ }, true);`;
435
447
  function watch(page, origin) {
436
448
  let problems = [];
437
449
  const urls = /* @__PURE__ */ new Map();
@@ -461,7 +473,7 @@ function watch(page, origin) {
461
473
  });
462
474
  page.on("Network.loadingFailed", (params) => {
463
475
  const url = urls.get(String(params["requestId"])) ?? "";
464
- if (own(url) && params["canceled"] !== true) problems.push(`request failed (${String(params["errorText"])}): ${url}`);
476
+ if ((own(url) || params["type"] === "Script") && params["canceled"] !== true) problems.push(`request failed (${String(params["errorText"])}): ${url}`);
465
477
  });
466
478
  return {
467
479
  reset: () => {
@@ -559,7 +571,7 @@ const CHECK_HELP = `Usage: site-pages check (--out <dir> | --url <url>) [options
559
571
  Opens the pages of the site in a headless Chromium at phone and desktop widths, in the light and
560
572
  the dark scheme, and fails when a page is wider than the screen, an element goes past the right
561
573
  edge, a text area hides its text, a page shows no text, or on a console error, an exception, a
562
- failed request of the site or a failed check of the probe.
574
+ failed request of the site, a script that does not load or a failed check of the probe.
563
575
 
564
576
  Options:
565
577
  --out <dir> The built site folder. The check serves it at --base.
@@ -571,7 +583,8 @@ Options:
571
583
  --schemes <list> light, dark or both (default: light,dark)
572
584
  --probe <file> A JavaScript file: the body of an async function with check(name, ok, detail),
573
585
  wait, until, $, $$, type and click. It runs on the first page, in the first
574
- scheme, at each width.
586
+ scheme, at each width. A .ts, .mts or .cts file is TypeScript: the check
587
+ removes its types and its line export {}.
575
588
  --shots <dir> The folder for the screenshots, report.json and summary.md
576
589
  --browser <file> The Chromium executable (default: $SITE_CHECK_BROWSER, the Chromium of
577
590
  Playwright, else Chrome or Edge)
@@ -642,10 +655,17 @@ async function runCheckCli(argv, io) {
642
655
  const at = (file) => isAbsolute(file) ? file : resolve(io.cwd, file);
643
656
  const probeFile = text("probe");
644
657
  let probe;
645
- if (probeFile !== void 0) try {
646
- probe = readFileSync(at(probeFile), "utf8");
647
- } catch (error) {
648
- return usage(`the probe file ${probeFile} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
658
+ if (probeFile !== void 0) {
659
+ try {
660
+ probe = readFileSync(at(probeFile), "utf8");
661
+ } catch (error) {
662
+ return usage(`the probe file ${probeFile} cannot be read: ${error instanceof Error ? error.message : String(error)}`);
663
+ }
664
+ if (TYPESCRIPT_PROBE.test(probeFile)) try {
665
+ probe = probeScript(probe);
666
+ } catch (error) {
667
+ return usage(`the types of the probe file ${probeFile} cannot be removed: ${error instanceof Error ? error.message : String(error)}`);
668
+ }
649
669
  }
650
670
  const shots = text("shots");
651
671
  const result = await checkSite({
package/build/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/check/browser.ts","../src/check/measure.ts","../src/check/serve.ts","../src/check/check.ts","../src/cli.ts"],"sourcesContent":["/**\n * A small client of the Chrome DevTools protocol for the `check` command. It starts a Chromium\n * browser (Chrome, Edge or the Chromium of Playwright) in headless mode and drives one page. It\n * uses only Node.js, so the check needs no package install.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\n\n/** The paths that `findBrowser` examines after the option and the Playwright folder. */\nfunction systemBrowsers(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[] {\n if (platform === \"win32\") {\n const roots = [env[\"PROGRAMFILES\"], env[\"PROGRAMFILES(X86)\"], env[\"LOCALAPPDATA\"]].filter((root): root is string => !!root);\n return roots.flatMap((root) => [join(root, \"Google/Chrome/Application/chrome.exe\"), join(root, \"Microsoft/Edge/Application/msedge.exe\")]);\n }\n if (platform === \"darwin\") {\n return [\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\", \"/Applications/Chromium.app/Contents/MacOS/Chromium\", \"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge\"];\n }\n const names = [\"google-chrome\", \"google-chrome-stable\", \"chromium\", \"chromium-browser\", \"microsoft-edge\"];\n const dirs = (env[\"PATH\"] ?? \"\").split(delimiter).filter(Boolean);\n return names.flatMap((name) => dirs.map((dir) => join(dir, name)));\n}\n\n/** The Chromium of the newest `chromium-<n>` folder of Playwright, or undefined. */\nfunction playwrightChromium(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string | undefined {\n const root =\n env[\"PLAYWRIGHT_BROWSERS_PATH\"] ||\n (platform === \"win32\" ? join(env[\"LOCALAPPDATA\"] ?? homedir(), \"ms-playwright\") : platform === \"darwin\" ? join(homedir(), \"Library/Caches/ms-playwright\") : join(homedir(), \".cache/ms-playwright\"));\n if (!existsSync(root)) return undefined;\n const builds = readdirSync(root)\n .map((name) => /^chromium-(\\d+)$/.exec(name))\n .filter((match): match is RegExpExecArray => match !== null)\n .sort((a, b) => Number(b[1]) - Number(a[1]));\n for (const [folder] of builds) {\n for (const sub of readdirSync(join(root, folder))) {\n const candidates =\n platform === \"win32\"\n ? [join(root, folder, sub, \"chrome.exe\")]\n : platform === \"darwin\"\n ? [join(root, folder, sub, \"Chromium.app/Contents/MacOS/Chromium\"), join(root, folder, sub, \"Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing\")]\n : [join(root, folder, sub, \"chrome\")];\n const found = candidates.find((file) => existsSync(file));\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/**\n * This function finds a Chromium browser. It examines the given path, then `$SITE_CHECK_BROWSER`,\n * then the newest Chromium of Playwright, then a Chrome or an Edge of the system.\n *\n * @returns the path of the executable, or undefined when there is none\n */\nexport function findBrowser(given?: string, env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string | undefined {\n const named = given || env[\"SITE_CHECK_BROWSER\"];\n if (named) return named;\n return playwrightChromium(platform, env) ?? systemBrowsers(platform, env).find((file) => existsSync(file));\n}\n\n/** A message of the DevTools protocol. */\ninterface Message {\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message: string };\n}\n\n/** An event handler of a page. */\ntype Listener = (params: Record<string, unknown>) => void;\n\n/** One page of a started browser. */\nexport interface Page {\n /** This function sends a command of the protocol and returns its result. */\n send(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;\n /** This function calls the listener on each event of the method. */\n on(method: string, listener: Listener): void;\n /** This function calls the listener on the next event of the method, or rejects after `ms`. */\n once(method: string, ms: number): Promise<Record<string, unknown>>;\n /** This function evaluates the expression in the page, and waits for a promise. */\n evaluate<T>(expression: string): Promise<T>;\n}\n\n/** A started browser. */\nexport interface Browser {\n page: Page;\n /** This function stops the browser and removes its profile. */\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * This function starts the browser in headless mode with a new profile, and connects to its page.\n * The browser picks a free port, so two checks can run at the same time.\n *\n * @throws Error when the browser does not start in `timeoutMs`\n */\nexport async function launch(executable: string, timeoutMs = 30_000): Promise<Browser> {\n const profile = mkdtempSync(join(tmpdir(), \"site-check-\"));\n const args = [\n \"--headless=new\",\n \"--remote-debugging-port=0\",\n `--user-data-dir=${profile}`,\n \"--no-first-run\",\n \"--no-default-browser-check\",\n \"--disable-gpu\",\n \"--disable-extensions\",\n \"--disable-background-networking\",\n \"--disable-sync\",\n \"--hide-scrollbars\",\n \"--mute-audio\",\n // The sandbox of Chromium needs user namespaces, which Ubuntu 24.04 refuses to a browser that the\n // system did not install. Playwright also starts Chromium with no sandbox.\n ...(process.platform === \"linux\" ? [\"--no-sandbox\"] : []),\n \"about:blank\",\n ];\n const child: ChildProcess = spawn(executable, args, { stdio: \"ignore\" });\n let exited: string | undefined;\n child.once(\"exit\", (code, signal) => (exited = `the browser stopped (code ${code}, signal ${signal})`));\n child.once(\"error\", (error) => (exited = `the browser did not start: ${error.message}`));\n const stop = async () => {\n if (child.exitCode === null && child.signalCode === null) {\n child.kill();\n await Promise.race([new Promise((resolve) => child.once(\"exit\", resolve)), sleep(5000)]);\n }\n rmSync(profile, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });\n };\n try {\n const portFile = join(profile, \"DevToolsActivePort\");\n const end = Date.now() + timeoutMs;\n let port = \"\";\n while (port === \"\") {\n if (exited !== undefined) throw new Error(`${executable}: ${exited}`);\n if (Date.now() > end) throw new Error(`${executable}: no DevTools port after ${timeoutMs} ms`);\n if (existsSync(portFile)) port = readFileSync(portFile, \"utf8\").split(\"\\n\")[0]?.trim() ?? \"\";\n if (port === \"\") await sleep(100);\n }\n let target: { type: string; webSocketDebuggerUrl: string } | undefined;\n while (target === undefined) {\n const list = (await (await fetch(`http://127.0.0.1:${port}/json/list`)).json()) as { type: string; webSocketDebuggerUrl: string }[];\n target = list.find((entry) => entry.type === \"page\");\n if (target === undefined) {\n if (Date.now() > end) throw new Error(`${executable}: no page target after ${timeoutMs} ms`);\n await sleep(100);\n }\n }\n const page = await connect(target.webSocketDebuggerUrl);\n return {\n page: page.page,\n close: async () => {\n page.close();\n await stop();\n },\n };\n } catch (error) {\n await stop();\n throw error;\n }\n}\n\nasync function connect(url: string): Promise<{ page: Page; close: () => void }> {\n const socket = new WebSocket(url);\n await new Promise<void>((resolve, reject) => {\n socket.addEventListener(\"open\", () => resolve(), { once: true });\n socket.addEventListener(\"error\", () => reject(new Error(`no connection to ${url}`)), { once: true });\n });\n let sequence = 0;\n const pending = new Map<number, { resolve: (value: Record<string, unknown>) => void; reject: (error: Error) => void }>();\n const listeners = new Map<string, Listener[]>();\n socket.addEventListener(\"message\", (event) => {\n const message = JSON.parse(String(event.data)) as Message;\n if (message.id !== undefined) {\n const call = pending.get(message.id);\n pending.delete(message.id);\n if (message.error) call?.reject(new Error(message.error.message));\n else call?.resolve(message.result ?? {});\n } else if (message.method) {\n for (const listener of listeners.get(message.method) ?? []) listener(message.params ?? {});\n }\n });\n socket.addEventListener(\"close\", () => {\n for (const call of pending.values()) call.reject(new Error(\"the browser closed the connection\"));\n pending.clear();\n });\n const page: Page = {\n send: (method, params = {}) =>\n new Promise((resolve, reject) => {\n const id = ++sequence;\n pending.set(id, { resolve, reject });\n socket.send(JSON.stringify({ id, method, params }));\n }),\n on: (method, listener) => listeners.set(method, [...(listeners.get(method) ?? []), listener]),\n once: (method, ms) =>\n new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n remove();\n reject(new Error(`no ${method} after ${ms} ms`));\n }, ms);\n const listener: Listener = (params) => {\n clearTimeout(timer);\n remove();\n resolve(params);\n };\n const remove = () => listeners.set(method, (listeners.get(method) ?? []).filter((entry) => entry !== listener));\n page.on(method, listener);\n }),\n evaluate: async <T>(expression: string): Promise<T> => {\n const reply = (await page.send(\"Runtime.evaluate\", { expression, awaitPromise: true, returnByValue: true })) as {\n result?: { value?: unknown };\n exceptionDetails?: { text?: string; exception?: { description?: string } };\n };\n if (reply.exceptionDetails) throw new Error(reply.exceptionDetails.exception?.description ?? reply.exceptionDetails.text ?? \"the expression failed\");\n return reply.result?.value as T;\n },\n };\n return { page, close: () => socket.close() };\n}\n","/**\n * The measurements that the `check` command makes in the page. Each is a string of JavaScript that\n * the browser evaluates, so the code can use only the APIs of the page.\n */\n\n/** The result of `MEASURE`. */\nexport interface Measure {\n innerWidth: number;\n scrollWidth: number;\n /** The height of the document, for the screenshot. */\n height: number;\n /** The number of characters of visible text. */\n text: number;\n /** The outermost elements that go past the right edge of the screen, at most 8. */\n past: string[];\n /** The text areas that hide a part of their text, at most 8. */\n clipped: string[];\n}\n\n/**\n * This expression measures the page. An element counts as past the edge when its right side is\n * more than half a pixel past the width of the document. These elements do not count:\n * - an element in a container that scrolls or clips (`overflow-x` other than `visible`, below `body`),\n * - an element of zero size, a hidden element, or a fixed element that is fully past the edge (a closed drawer),\n * - an element in `.sr`, `.sr-only`, `.visually-hidden` or `.skip` (text for screen readers and skip links),\n * - an element in a `pre`, other than the `pre` itself.\n * Of a chain of elements past the edge, only the outermost one counts.\n */\nexport const MEASURE = `(() => {\n const root = document.documentElement;\n const w = root.clientWidth;\n const name = (e) => e.tagName.toLowerCase() + (e.id ? \"#\" + e.id : \"\") + (typeof e.className === \"string\" && e.className.trim() ? \".\" + e.className.trim().split(/\\\\s+/).slice(0, 3).join(\".\") : \"\");\n const inScroller = (e) => {\n for (let p = e.parentElement; p && p !== document.body && p !== root; p = p.parentElement) {\n if (getComputedStyle(p).overflowX !== \"visible\") return true;\n }\n return false;\n };\n const counts = (e) => {\n const r = e.getBoundingClientRect();\n if (r.width === 0 || r.height === 0 || r.right <= w + 0.5) return false;\n if (e.closest(\".sr,.sr-only,.visually-hidden,.skip\")) return false;\n if (e.closest(\"pre\") && e.tagName !== \"PRE\") return false;\n const s = getComputedStyle(e);\n if (s.visibility === \"hidden\" || s.display === \"none\") return false;\n if (s.position === \"fixed\" && r.left >= w) return false;\n return !inScroller(e);\n };\n const over = new Set([...document.querySelectorAll(\"body *\")].filter(counts));\n const past = [...over]\n .filter((e) => { for (let p = e.parentElement; p; p = p.parentElement) if (over.has(p)) return false; return true; })\n .map((e) => name(e) + \" right=\" + Math.round(e.getBoundingClientRect().right));\n const clipped = [...document.querySelectorAll(\"textarea\")]\n .filter((e) => { const s = getComputedStyle(e); return (s.overflowY === \"hidden\" || s.overflowY === \"clip\") && e.getBoundingClientRect().height > 0 && e.scrollHeight > e.clientHeight + 1; })\n .map((e) => name(e) + \" \" + e.scrollHeight + \">\" + e.clientHeight);\n return {\n innerWidth,\n scrollWidth: root.scrollWidth,\n height: Math.max(root.scrollHeight, document.body ? document.body.scrollHeight : 0),\n text: (document.body ? document.body.innerText : \"\").trim().length,\n past: past.slice(0, 8),\n clipped: clipped.slice(0, 8),\n };\n})()`;\n\n/** One check of a probe. */\nexport interface ProbeCheck {\n name: string;\n ok: boolean;\n detail?: string;\n}\n\n/**\n * This function wraps the code of a probe file into an expression. The code is the body of an async\n * function with these names:\n * - `check(name, ok, detail)` records a check,\n * - `wait(ms)` waits,\n * - `until(fn, ms)` waits until `fn()` gives a true value, at most `ms` (default 5000), and returns the value,\n * - `$(selector)` and `$$(selector)` find elements,\n * - `type(element, text)` writes the text into an input or a text area, with an `input` event,\n * - `click(element)` clicks an element, or the first element of a selector.\n * An exception stops the probe, and it counts as a failed check.\n */\nexport function probeExpression(code: string): string {\n return `(async () => {\n const __checks = [];\n const __text = (v) => { if (v === undefined) return undefined; if (typeof v === \"string\") return v; try { return JSON.stringify(v); } catch { return String(v); } };\n const check = (name, ok, detail) => { __checks.push({ name: String(name), ok: !!ok, ...(ok ? {} : { detail: __text(detail) }) }); return !!ok; };\n const wait = (ms) => new Promise((r) => setTimeout(r, ms));\n const until = async (fn, ms = 5000) => { const end = Date.now() + ms; for (;;) { const v = await fn(); if (v) return v; if (Date.now() > end) return v; await wait(50); } };\n const $ = (s) => document.querySelector(s);\n const $$ = (s) => [...document.querySelectorAll(s)];\n const __el = (e) => { const el = typeof e === \"string\" ? document.querySelector(e) : e; if (!el) throw new Error(\"no element: \" + e); return el; };\n const type = (e, text) => { const el = __el(e); el.focus(); el.value = text; el.dispatchEvent(new Event(\"input\", { bubbles: true })); el.dispatchEvent(new Event(\"change\", { bubbles: true })); };\n const click = (e) => __el(e).click();\n try {\n await (async () => {\n${code}\n })();\n } catch (e) {\n __checks.push({ name: \"the probe runs to its end\", ok: false, detail: String((e && e.stack) || e) });\n }\n return __checks;\n})()`;\n}\n","/**\n * A static file server for the `check` command. It serves a built site folder at the path of the\n * site home, as GitHub Pages does. Thus the links of the site work as on the live site.\n */\n\nimport { createReadStream, existsSync, statSync } from \"node:fs\";\nimport { createServer, type Server } from \"node:http\";\nimport { extname, join, normalize, resolve, sep } from \"node:path\";\n\nconst TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n \".wasm\": \"application/wasm\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".md\": \"text/markdown; charset=utf-8\",\n \".xml\": \"application/xml\",\n \".webmanifest\": \"application/manifest+json\",\n \".map\": \"application/json; charset=utf-8\",\n};\n\n/**\n * This function maps the path of a request to a file of the folder, as GitHub Pages does. A folder\n * gives its `index.html`. For a path with no extension, the function also tries `<path>.html`.\n *\n * @returns the absolute file, or undefined when the path is outside the base or the file is missing\n */\nexport function resolveFile(root: string, base: string, pathname: string): string | undefined {\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return undefined;\n }\n const home = base.endsWith(\"/\") ? base : `${base}/`;\n if (decoded === home.slice(0, -1)) decoded = home;\n if (!decoded.startsWith(home)) return undefined;\n const top = resolve(root);\n const file = normalize(join(top, decoded.slice(home.length)));\n if (file !== top && !file.startsWith(top + sep)) return undefined;\n const candidates = [file, join(file, \"index.html\"), `${file}.html`];\n return candidates.find((candidate) => existsSync(candidate) && statSync(candidate).isFile());\n}\n\n/** A started server. */\nexport interface StaticServer {\n /** The URL of the site home, for example `http://127.0.0.1:50123/client/`. */\n url: string;\n close(): Promise<void>;\n}\n\n/**\n * This function serves the folder at `base` on a free port of 127.0.0.1. A missing file gives the\n * status 404 with the `404.html` of the folder, when it has one.\n */\nexport async function serve(root: string, base: string): Promise<StaticServer> {\n const server: Server = createServer((request, response) => {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n const home = base.endsWith(\"/\") ? base : `${base}/`;\n if (pathname === home.slice(0, -1) && home !== \"/\") {\n response.writeHead(301, { location: home }).end();\n return;\n }\n const file = resolveFile(root, base, pathname);\n const missing = join(resolve(root), \"404.html\");\n const send = file ?? (existsSync(missing) ? missing : undefined);\n if (send === undefined) {\n response.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(`404: ${pathname}\\n`);\n return;\n }\n response.writeHead(file ? 200 : 404, { \"content-type\": TYPES[extname(send).toLowerCase()] ?? \"application/octet-stream\", \"cache-control\": \"no-store\" });\n createReadStream(send).pipe(response);\n });\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail);\n server.listen(0, \"127.0.0.1\", () => done());\n });\n const address = server.address();\n if (address === null || typeof address === \"string\") throw new Error(\"the server has no port\");\n return {\n url: `http://127.0.0.1:${address.port}${base.endsWith(\"/\") ? base : `${base}/`}`,\n close: () => new Promise((done) => server.close(() => done())),\n };\n}\n","/**\n * The `site-pages check` command. It opens the pages of a built site (or of a live URL) in a\n * headless Chromium at phone and desktop widths, in the light and the dark scheme.\n *\n * A view fails when the page is wider than the screen or an element goes past the right edge. It\n * also fails when a text area hides its text or the page shows no text. A console error, an\n * exception, a failed request of the site and a failed check of the probe also fail it. The command\n * writes a screenshot of each view.\n */\n\nimport { appendFileSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { findBrowser, launch, type Page } from \"./browser.ts\";\nimport { MEASURE, probeExpression, type Measure, type ProbeCheck } from \"./measure.ts\";\nimport { serve } from \"./serve.ts\";\n\n/** The options of `checkSite`. */\nexport interface CheckOptions {\n /** The built site folder. Give `out` or `url`. */\n out?: string | undefined;\n /** The path of the site home, for `out`, for example `/client/`. */\n base?: string | undefined;\n /** The URL of a live site home. Give `out` or `url`. */\n url?: string | undefined;\n /** The pages, from the site home, for example `/` and `/releases/`. */\n pages: readonly string[];\n /** The widths in CSS pixels. A width under 768 is a phone. */\n widths: readonly number[];\n /** The color schemes. */\n schemes: readonly (\"light\" | \"dark\")[];\n /** The code of a probe: the body of an async function (see `probeExpression`). It runs on the first page, in the light scheme, at each width. */\n probe?: string | undefined;\n /** The folder for the screenshots, `report.json` and `summary.md`. */\n shots?: string | undefined;\n /** The browser executable. */\n browser?: string | undefined;\n /** The time to wait after the load event, for the scripts of the page. */\n settleMs: number;\n /** The time limit of a page load. */\n timeoutMs: number;\n log?: ((line: string) => void) | undefined;\n}\n\n/** The result of one page at one width and scheme. */\nexport interface ViewResult {\n page: string;\n width: number;\n scheme: \"light\" | \"dark\";\n ok: boolean;\n /** What failed. */\n problems: string[];\n measure?: Measure | undefined;\n probe?: ProbeCheck[] | undefined;\n /** The file of the screenshot. */\n shot?: string | undefined;\n}\n\n/** The result of `checkSite`. */\nexport interface CheckResult {\n ok: boolean;\n url: string;\n browser: string;\n views: ViewResult[];\n}\n\n/** This function gives the file name part of a page: `/` is `home`, `/releases/` is `releases`. */\nexport function pageSlug(page: string): string {\n const slug = page.replace(/^\\/+|\\/+$/g, \"\").replace(/[^A-Za-z0-9._-]+/g, \"_\");\n return slug === \"\" ? \"home\" : slug;\n}\n\n/**\n * This function checks the site. It starts one browser and, for `out`, one server, and stops both at\n * the end.\n *\n * @throws Error when there is no browser, or the browser does not start\n */\nexport async function checkSite(options: CheckOptions): Promise<CheckResult> {\n const log = options.log ?? (() => {});\n const executable = findBrowser(options.browser);\n if (executable === undefined) throw new Error(\"no Chromium browser was found: give --browser, set SITE_CHECK_BROWSER, or install the Chromium of Playwright\");\n if (options.pages.length === 0) throw new Error(\"no page to check\");\n const server = options.out !== undefined ? await serve(options.out, options.base ?? \"/\") : undefined;\n const home = server?.url ?? options.url;\n if (home === undefined) throw new Error(\"give out or url\");\n const homeUrl = new URL(home.endsWith(\"/\") ? home : `${home}/`);\n const browser = await launch(executable, options.timeoutMs);\n const views: ViewResult[] = [];\n try {\n const { page } = browser;\n const events = watch(page, homeUrl.origin);\n await Promise.all([page.send(\"Page.enable\"), page.send(\"Runtime.enable\"), page.send(\"Network.enable\")]);\n if (options.shots) mkdirSync(options.shots, { recursive: true });\n for (const [index, path] of options.pages.entries()) {\n const target = new URL(path.replace(/^\\/+/, \"\"), homeUrl).href;\n for (const width of options.widths) {\n for (const scheme of options.schemes) {\n const withProbe = options.probe !== undefined && index === 0 && scheme === options.schemes[0];\n const view = await checkView(page, events, { target, path, width, scheme, withProbe, options });\n views.push(view);\n log(`${view.ok ? \"PASS\" : \"FAIL\"} ${path} ${width} ${scheme}${view.measure ? ` scrollWidth=${view.measure.scrollWidth} innerWidth=${view.measure.innerWidth}` : \"\"}${view.probe ? ` probe ${view.probe.filter((c) => c.ok).length}/${view.probe.length}` : \"\"}${view.problems.length > 0 ? `\\n - ${view.problems.join(\"\\n - \")}` : \"\"}`);\n }\n }\n }\n } finally {\n await browser.close();\n await server?.close();\n }\n const result: CheckResult = { ok: views.length > 0 && views.every((view) => view.ok), url: homeUrl.href, browser: executable, views };\n if (options.shots) {\n writeFileSync(join(options.shots, \"report.json\"), `${JSON.stringify(result, null, 2)}\\n`);\n writeFileSync(join(options.shots, \"summary.md\"), summary(result));\n }\n return result;\n}\n\n/** The problems that the events of the page gave, since the last `reset`. */\ninterface Events {\n reset(): void;\n problems(): string[];\n}\n\nfunction watch(page: Page, origin: string): Events {\n let problems: string[] = [];\n const urls = new Map<string, string>();\n const own = (url: string) => {\n try {\n const parsed = new URL(url);\n // A browser asks for /favicon.ico on its own, also for a site under a path.\n return parsed.origin === origin && parsed.pathname !== \"/favicon.ico\";\n } catch {\n return false;\n }\n };\n page.on(\"Runtime.exceptionThrown\", (params) => {\n const details = params[\"exceptionDetails\"] as { text?: string; exception?: { description?: string } };\n problems.push(`exception: ${(details.exception?.description ?? details.text ?? \"\").split(\"\\n\")[0]}`);\n });\n page.on(\"Runtime.consoleAPICalled\", (params) => {\n if (params[\"type\"] !== \"error\" && params[\"type\"] !== \"assert\") return;\n const args = (params[\"args\"] as { value?: unknown; description?: string }[]) ?? [];\n problems.push(`console.error: ${args.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \").slice(0, 300)}`);\n });\n page.on(\"Network.requestWillBeSent\", (params) => {\n urls.set(String(params[\"requestId\"]), String((params[\"request\"] as { url: string }).url));\n });\n page.on(\"Network.responseReceived\", (params) => {\n const response = params[\"response\"] as { url: string; status: number };\n if (response.status >= 400 && own(response.url)) problems.push(`HTTP ${response.status}: ${response.url}`);\n });\n page.on(\"Network.loadingFailed\", (params) => {\n const url = urls.get(String(params[\"requestId\"])) ?? \"\";\n if (own(url) && params[\"canceled\"] !== true) problems.push(`request failed (${String(params[\"errorText\"])}): ${url}`);\n });\n return {\n reset: () => {\n problems = [];\n },\n problems: () => [...new Set(problems)],\n };\n}\n\ninterface ViewInput {\n target: string;\n path: string;\n width: number;\n scheme: \"light\" | \"dark\";\n withProbe: boolean;\n options: CheckOptions;\n}\n\nasync function checkView(page: Page, events: Events, input: ViewInput): Promise<ViewResult> {\n const { target, path, width, scheme, withProbe, options } = input;\n const view: ViewResult = { page: path, width, scheme, ok: false, problems: [] };\n try {\n await page.send(\"Emulation.setDeviceMetricsOverride\", { width, height: 900, deviceScaleFactor: 1, mobile: width < 768 });\n await page.send(\"Emulation.setEmulatedMedia\", { features: [{ name: \"prefers-color-scheme\", value: scheme }] });\n events.reset();\n const loaded = page.once(\"Page.loadEventFired\", options.timeoutMs);\n const navigation = (await page.send(\"Page.navigate\", { url: target })) as { errorText?: string };\n if (navigation.errorText) {\n loaded.catch(() => {});\n throw new Error(`the page did not open: ${navigation.errorText}`);\n }\n await loaded;\n await page.evaluate(\"document.fonts ? document.fonts.ready.then(() => true) : true\");\n await new Promise((done) => setTimeout(done, options.settleMs));\n const measure = await page.evaluate<Measure>(MEASURE);\n view.measure = measure;\n // The screen width, not innerWidth: a phone browser can zoom out a page that is too wide.\n if (measure.scrollWidth > width) view.problems.push(`the page is wider than the screen: ${measure.scrollWidth} > ${width}`);\n for (const past of measure.past) view.problems.push(`past the right edge: ${past}`);\n for (const clipped of measure.clipped) view.problems.push(`a text area hides its text: ${clipped}`);\n if (measure.text === 0) view.problems.push(\"the page shows no text\");\n if (options.shots) {\n const file = join(options.shots, `${pageSlug(path)}-${width}-${scheme}.png`);\n const height = Math.min(Math.max(measure.height, 1), 8000);\n const shot = (await page.send(\"Page.captureScreenshot\", { format: \"png\", captureBeyondViewport: true, clip: { x: 0, y: 0, width, height, scale: 1 } })) as { data: string };\n writeFileSync(file, Buffer.from(shot.data, \"base64\"));\n view.shot = file;\n }\n if (withProbe && options.probe !== undefined) {\n const checks = (await page.evaluate<ProbeCheck[] | undefined>(probeExpression(options.probe))) ?? [];\n view.probe = checks;\n if (checks.length === 0) view.problems.push(\"the probe made no check\");\n for (const check of checks.filter((entry) => !entry.ok)) view.problems.push(`probe: ${check.name}${check.detail ? ` (${check.detail})` : \"\"}`);\n }\n } catch (error) {\n view.problems.push(error instanceof Error ? error.message : String(error));\n }\n view.problems.push(...events.problems());\n view.ok = view.problems.length === 0;\n return view;\n}\n\n/** This function makes a text safe for a cell of a Markdown table. It escapes `\\`, `|`, `<` and `>`. It changes each new line to a space. */\nexport function cell(text: string): string {\n return text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\\r?\\n/g, \" \");\n}\n\n/** This function gives the Markdown summary of a result, for the job summary of a workflow. */\nexport function summary(result: CheckResult): string {\n const failed = result.views.filter((view) => !view.ok);\n const lines = [\n `### Site check: ${result.ok ? \"passed\" : \"failed\"}`,\n \"\",\n `${result.views.length - failed.length} of ${result.views.length} views passed, at ${result.url}.`,\n \"\",\n \"| Page | Width | Scheme | Result | Problems |\",\n \"| --- | ---: | --- | --- | --- |\",\n ...result.views.map(\n (view) =>\n `| \\`${view.page}\\` | ${view.width} | ${view.scheme} | ${view.ok ? \"pass\" : \"**fail**\"}${view.probe ? ` (probe ${view.probe.filter((c) => c.ok).length}/${view.probe.length})` : \"\"} | ${view.problems.map(cell).join(\"<br>\")} |`,\n ),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/** The input and output of the CLI. */\nexport interface CheckIo {\n cwd: string;\n env: NodeJS.ProcessEnv;\n stdout: (text: string) => void;\n stderr: (text: string) => void;\n}\n\nexport const CHECK_HELP = `Usage: site-pages check (--out <dir> | --url <url>) [options]\n\nOpens the pages of the site in a headless Chromium at phone and desktop widths, in the light and\nthe dark scheme, and fails when a page is wider than the screen, an element goes past the right\nedge, a text area hides its text, a page shows no text, or on a console error, an exception, a\nfailed request of the site or a failed check of the probe.\n\nOptions:\n --out <dir> The built site folder. The check serves it at --base.\n --url <url> The URL of a live site home, in place of --out\n --repo <owner/name> The GitHub repository, for the default base (default: $GITHUB_REPOSITORY)\n --base </name/> The path of the site home (default: \"/<name>/\", or \"/\" for <owner>.github.io)\n --pages <paths> The pages, from the site home, separated by commas (default: /)\n --widths <px> The widths, separated by commas (default: 360,400,1280)\n --schemes <list> light, dark or both (default: light,dark)\n --probe <file> A JavaScript file: the body of an async function with check(name, ok, detail),\n wait, until, $, $$, type and click. It runs on the first page, in the first\n scheme, at each width.\n --shots <dir> The folder for the screenshots, report.json and summary.md\n --browser <file> The Chromium executable (default: $SITE_CHECK_BROWSER, the Chromium of\n Playwright, else Chrome or Edge)\n --settle <ms> The wait after the load event (default: 1500)\n --timeout <ms> The time limit of a page load (default: 30000)\n --help Shows this text\n\nWith $GITHUB_STEP_SUMMARY, the check adds its table to the job summary.\n`;\n\n/** This function runs the `check` command with its arguments, without the word `check`. */\nexport async function runCheckCli(argv: readonly string[], io: CheckIo): Promise<number> {\n let values: Record<string, string | boolean | undefined>;\n try {\n ({ values } = parseArgs({\n args: [...argv],\n allowPositionals: false,\n options: {\n out: { type: \"string\" },\n url: { type: \"string\" },\n repo: { type: \"string\" },\n base: { type: \"string\" },\n pages: { type: \"string\" },\n widths: { type: \"string\" },\n schemes: { type: \"string\" },\n probe: { type: \"string\" },\n shots: { type: \"string\" },\n browser: { type: \"string\" },\n settle: { type: \"string\" },\n timeout: { type: \"string\" },\n help: { type: \"boolean\" },\n },\n }));\n } catch (error) {\n io.stderr(`site-pages check: ${error instanceof Error ? error.message : String(error)}\\n\\n${CHECK_HELP}`);\n return 2;\n }\n if (values[\"help\"]) {\n io.stdout(CHECK_HELP);\n return 0;\n }\n const usage = (message: string) => {\n io.stderr(`site-pages check: ${message}\\n\\n${CHECK_HELP}`);\n return 2;\n };\n const text = (key: string) => (typeof values[key] === \"string\" ? (values[key] as string) : undefined);\n const list = (key: string, fallback: string) => (text(key) ?? fallback).split(\",\").map((entry) => entry.trim()).filter(Boolean);\n const out = text(\"out\");\n const url = text(\"url\");\n if ((out === undefined) === (url === undefined)) return usage(\"give --out or --url, not both\");\n const widths = list(\"widths\", \"360,400,1280\").map(Number);\n if (widths.length === 0 || widths.some((width) => !Number.isInteger(width) || width < 200 || width > 4000)) return usage(\"--widths must be whole numbers from 200 to 4000\");\n const schemes = list(\"schemes\", \"light,dark\");\n if (schemes.length === 0 || schemes.some((scheme) => scheme !== \"light\" && scheme !== \"dark\")) return usage(\"--schemes must be light, dark or both\");\n const pages = list(\"pages\", \"/\");\n if (pages.length === 0) return usage(\"--pages has no page\");\n // Git Bash changes a bare \"/\" into \"C:/Program Files/Git/\". A page is a path, with no scheme or drive.\n const notPath = pages.find((entry) => entry.includes(\":\") || entry.includes(\"\\\\\"));\n if (notPath !== undefined) return usage(`a page is a path from the site home, not \"${notPath}\" (in Git Bash, set MSYS_NO_PATHCONV=1)`);\n const settleMs = Number(text(\"settle\") ?? 1500);\n const timeoutMs = Number(text(\"timeout\") ?? 30000);\n if (!(settleMs >= 0) || !(timeoutMs > 0)) return usage(\"--settle and --timeout must be numbers of milliseconds\");\n let base = text(\"base\");\n if (out !== undefined && base === undefined) {\n const name = (text(\"repo\") ?? io.env[\"GITHUB_REPOSITORY\"] ?? \"\").split(\"/\")[1];\n if (!name) return usage(\"give --base, --repo or set GITHUB_REPOSITORY\");\n base = /\\.github\\.io$/i.test(name) ? \"/\" : `/${name}/`;\n }\n if (base !== undefined) base = `/${base.replace(/^\\/+|\\/+$/g, \"\")}/`.replace(/^\\/\\/$/, \"/\");\n const at = (file: string) => (isAbsolute(file) ? file : resolve(io.cwd, file));\n const probeFile = text(\"probe\");\n let probe: string | undefined;\n if (probeFile !== undefined) {\n try {\n probe = readFileSync(at(probeFile), \"utf8\");\n } catch (error) {\n return usage(`the probe file ${probeFile} cannot be read: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n const shots = text(\"shots\");\n const result = await checkSite({\n out: out === undefined ? undefined : at(out),\n base,\n url,\n pages,\n widths,\n schemes: schemes as (\"light\" | \"dark\")[],\n probe,\n shots: shots === undefined ? undefined : at(shots),\n browser: text(\"browser\"),\n settleMs,\n timeoutMs,\n log: (line) => io.stdout(`${line}\\n`),\n });\n const failed = result.views.filter((view) => !view.ok).length;\n io.stdout(`site-pages check: ${result.views.length - failed} of ${result.views.length} views passed (${result.browser}).\\n`);\n const step = io.env[\"GITHUB_STEP_SUMMARY\"];\n if (step) appendFileSync(step, summary(result));\n return result.ok ? 0 : 1;\n}\n","#!/usr/bin/env node\n// The bin `site-pages`. The work is in build.ts and check/check.ts, so a test can run the same CLI with its own fetch.\nimport { runCli } from \"./build.ts\";\nimport { runCheckCli } from \"./check/check.ts\";\n\nconst argv = process.argv.slice(2);\nconst io = {\n cwd: process.cwd(),\n env: process.env,\n stdout: (text: string) => process.stdout.write(text),\n stderr: (text: string) => process.stderr.write(text),\n};\n(argv[0] === \"check\" ? runCheckCli(argv.slice(1), io) : runCli(argv, io)).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`site-pages: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}\\n`);\n process.exitCode = 1;\n },\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/check/browser.ts","../src/check/measure.ts","../src/check/serve.ts","../src/check/check.ts","../src/cli.ts"],"sourcesContent":["/**\n * A small client of the Chrome DevTools protocol for the `check` command. It starts a Chromium\n * browser (Chrome, Edge or the Chromium of Playwright) in headless mode and drives one page. It\n * uses only Node.js, so the check needs no package install.\n */\n\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { existsSync, mkdtempSync, readdirSync, readFileSync, rmSync } from \"node:fs\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { delimiter, join } from \"node:path\";\n\n/** The paths that `findBrowser` examines after the option and the Playwright folder. */\nfunction systemBrowsers(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string[] {\n if (platform === \"win32\") {\n const roots = [env[\"PROGRAMFILES\"], env[\"PROGRAMFILES(X86)\"], env[\"LOCALAPPDATA\"]].filter((root): root is string => !!root);\n return roots.flatMap((root) => [join(root, \"Google/Chrome/Application/chrome.exe\"), join(root, \"Microsoft/Edge/Application/msedge.exe\")]);\n }\n if (platform === \"darwin\") {\n return [\"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome\", \"/Applications/Chromium.app/Contents/MacOS/Chromium\", \"/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge\"];\n }\n const names = [\"google-chrome\", \"google-chrome-stable\", \"chromium\", \"chromium-browser\", \"microsoft-edge\"];\n const dirs = (env[\"PATH\"] ?? \"\").split(delimiter).filter(Boolean);\n return names.flatMap((name) => dirs.map((dir) => join(dir, name)));\n}\n\n/** The Chromium of the newest `chromium-<n>` folder of Playwright, or undefined. */\nfunction playwrightChromium(platform: NodeJS.Platform, env: NodeJS.ProcessEnv): string | undefined {\n const root =\n env[\"PLAYWRIGHT_BROWSERS_PATH\"] ||\n (platform === \"win32\" ? join(env[\"LOCALAPPDATA\"] ?? homedir(), \"ms-playwright\") : platform === \"darwin\" ? join(homedir(), \"Library/Caches/ms-playwright\") : join(homedir(), \".cache/ms-playwright\"));\n if (!existsSync(root)) return undefined;\n const builds = readdirSync(root)\n .map((name) => /^chromium-(\\d+)$/.exec(name))\n .filter((match): match is RegExpExecArray => match !== null)\n .sort((a, b) => Number(b[1]) - Number(a[1]));\n for (const [folder] of builds) {\n for (const sub of readdirSync(join(root, folder))) {\n const candidates =\n platform === \"win32\"\n ? [join(root, folder, sub, \"chrome.exe\")]\n : platform === \"darwin\"\n ? [join(root, folder, sub, \"Chromium.app/Contents/MacOS/Chromium\"), join(root, folder, sub, \"Google Chrome for Testing.app/Contents/MacOS/Google Chrome for Testing\")]\n : [join(root, folder, sub, \"chrome\")];\n const found = candidates.find((file) => existsSync(file));\n if (found) return found;\n }\n }\n return undefined;\n}\n\n/**\n * This function finds a Chromium browser. It examines the given path, then `$SITE_CHECK_BROWSER`,\n * then the newest Chromium of Playwright, then a Chrome or an Edge of the system.\n *\n * @returns the path of the executable, or undefined when there is none\n */\nexport function findBrowser(given?: string, env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string | undefined {\n const named = given || env[\"SITE_CHECK_BROWSER\"];\n if (named) return named;\n return playwrightChromium(platform, env) ?? systemBrowsers(platform, env).find((file) => existsSync(file));\n}\n\n/** A message of the DevTools protocol. */\ninterface Message {\n id?: number;\n method?: string;\n params?: Record<string, unknown>;\n result?: Record<string, unknown>;\n error?: { message: string };\n}\n\n/** An event handler of a page. */\ntype Listener = (params: Record<string, unknown>) => void;\n\n/** One page of a started browser. */\nexport interface Page {\n /** This function sends a command of the protocol and returns its result. */\n send(method: string, params?: Record<string, unknown>): Promise<Record<string, unknown>>;\n /** This function calls the listener on each event of the method. */\n on(method: string, listener: Listener): void;\n /** This function calls the listener on the next event of the method, or rejects after `ms`. */\n once(method: string, ms: number): Promise<Record<string, unknown>>;\n /** This function evaluates the expression in the page, and waits for a promise. */\n evaluate<T>(expression: string): Promise<T>;\n}\n\n/** A started browser. */\nexport interface Browser {\n page: Page;\n /** This function stops the browser and removes its profile. */\n close(): Promise<void>;\n}\n\nconst sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * This function starts the browser in headless mode with a new profile, and connects to its page.\n * The browser picks a free port, so two checks can run at the same time.\n *\n * @throws Error when the browser does not start in `timeoutMs`\n */\nexport async function launch(executable: string, timeoutMs = 30_000): Promise<Browser> {\n const profile = mkdtempSync(join(tmpdir(), \"site-check-\"));\n const args = [\n \"--headless=new\",\n \"--remote-debugging-port=0\",\n `--user-data-dir=${profile}`,\n \"--no-first-run\",\n \"--no-default-browser-check\",\n \"--disable-gpu\",\n \"--disable-extensions\",\n \"--disable-background-networking\",\n \"--disable-sync\",\n \"--hide-scrollbars\",\n \"--mute-audio\",\n // The sandbox of Chromium needs user namespaces, which Ubuntu 24.04 refuses to a browser that the\n // system did not install. Playwright also starts Chromium with no sandbox.\n ...(process.platform === \"linux\" ? [\"--no-sandbox\"] : []),\n \"about:blank\",\n ];\n const child: ChildProcess = spawn(executable, args, { stdio: \"ignore\" });\n let exited: string | undefined;\n child.once(\"exit\", (code, signal) => (exited = `the browser stopped (code ${code}, signal ${signal})`));\n child.once(\"error\", (error) => (exited = `the browser did not start: ${error.message}`));\n const stop = async () => {\n if (child.exitCode === null && child.signalCode === null) {\n child.kill();\n await Promise.race([new Promise((resolve) => child.once(\"exit\", resolve)), sleep(5000)]);\n }\n rmSync(profile, { recursive: true, force: true, maxRetries: 5, retryDelay: 200 });\n };\n try {\n const portFile = join(profile, \"DevToolsActivePort\");\n const end = Date.now() + timeoutMs;\n let port = \"\";\n while (port === \"\") {\n if (exited !== undefined) throw new Error(`${executable}: ${exited}`);\n if (Date.now() > end) throw new Error(`${executable}: no DevTools port after ${timeoutMs} ms`);\n if (existsSync(portFile)) port = readFileSync(portFile, \"utf8\").split(\"\\n\")[0]?.trim() ?? \"\";\n if (port === \"\") await sleep(100);\n }\n let target: { type: string; webSocketDebuggerUrl: string } | undefined;\n while (target === undefined) {\n const list = (await (await fetch(`http://127.0.0.1:${port}/json/list`)).json()) as { type: string; webSocketDebuggerUrl: string }[];\n target = list.find((entry) => entry.type === \"page\");\n if (target === undefined) {\n if (Date.now() > end) throw new Error(`${executable}: no page target after ${timeoutMs} ms`);\n await sleep(100);\n }\n }\n const page = await connect(target.webSocketDebuggerUrl);\n return {\n page: page.page,\n close: async () => {\n page.close();\n await stop();\n },\n };\n } catch (error) {\n await stop();\n throw error;\n }\n}\n\nasync function connect(url: string): Promise<{ page: Page; close: () => void }> {\n const socket = new WebSocket(url);\n await new Promise<void>((resolve, reject) => {\n socket.addEventListener(\"open\", () => resolve(), { once: true });\n socket.addEventListener(\"error\", () => reject(new Error(`no connection to ${url}`)), { once: true });\n });\n let sequence = 0;\n const pending = new Map<number, { resolve: (value: Record<string, unknown>) => void; reject: (error: Error) => void }>();\n const listeners = new Map<string, Listener[]>();\n socket.addEventListener(\"message\", (event) => {\n const message = JSON.parse(String(event.data)) as Message;\n if (message.id !== undefined) {\n const call = pending.get(message.id);\n pending.delete(message.id);\n if (message.error) call?.reject(new Error(message.error.message));\n else call?.resolve(message.result ?? {});\n } else if (message.method) {\n for (const listener of listeners.get(message.method) ?? []) listener(message.params ?? {});\n }\n });\n socket.addEventListener(\"close\", () => {\n for (const call of pending.values()) call.reject(new Error(\"the browser closed the connection\"));\n pending.clear();\n });\n const page: Page = {\n send: (method, params = {}) =>\n new Promise((resolve, reject) => {\n const id = ++sequence;\n pending.set(id, { resolve, reject });\n socket.send(JSON.stringify({ id, method, params }));\n }),\n on: (method, listener) => listeners.set(method, [...(listeners.get(method) ?? []), listener]),\n once: (method, ms) =>\n new Promise((resolve, reject) => {\n const timer = setTimeout(() => {\n remove();\n reject(new Error(`no ${method} after ${ms} ms`));\n }, ms);\n const listener: Listener = (params) => {\n clearTimeout(timer);\n remove();\n resolve(params);\n };\n const remove = () => listeners.set(method, (listeners.get(method) ?? []).filter((entry) => entry !== listener));\n page.on(method, listener);\n }),\n evaluate: async <T>(expression: string): Promise<T> => {\n const reply = (await page.send(\"Runtime.evaluate\", { expression, awaitPromise: true, returnByValue: true })) as {\n result?: { value?: unknown };\n exceptionDetails?: { text?: string; exception?: { description?: string } };\n };\n if (reply.exceptionDetails) throw new Error(reply.exceptionDetails.exception?.description ?? reply.exceptionDetails.text ?? \"the expression failed\");\n return reply.result?.value as T;\n },\n };\n return { page, close: () => socket.close() };\n}\n","/**\n * The measurements that the `check` command makes in the page. Each is a string of JavaScript that\n * the browser evaluates, so the code can use only the APIs of the page.\n */\n\n/** The result of `MEASURE`. */\nexport interface Measure {\n innerWidth: number;\n scrollWidth: number;\n /** The height of the document, for the screenshot. */\n height: number;\n /** The number of characters of visible text. */\n text: number;\n /** The outermost elements that go past the right edge of the screen, at most 8. */\n past: string[];\n /** The text areas that hide a part of their text, at most 8. */\n clipped: string[];\n}\n\n/**\n * This expression measures the page. An element counts as past the edge when its right side is\n * more than half a pixel past the width of the document. These elements do not count:\n * - an element in a container that scrolls or clips (`overflow-x` other than `visible`, below `body`),\n * - an element of zero size, a hidden element, or a fixed element that is fully past the edge (a closed drawer),\n * - an element in `.sr`, `.sr-only`, `.visually-hidden` or `.skip` (text for screen readers and skip links),\n * - an element in a `pre`, other than the `pre` itself.\n * Of a chain of elements past the edge, only the outermost one counts.\n */\nexport const MEASURE = `(() => {\n const root = document.documentElement;\n const w = root.clientWidth;\n const name = (e) => e.tagName.toLowerCase() + (e.id ? \"#\" + e.id : \"\") + (typeof e.className === \"string\" && e.className.trim() ? \".\" + e.className.trim().split(/\\\\s+/).slice(0, 3).join(\".\") : \"\");\n const inScroller = (e) => {\n for (let p = e.parentElement; p && p !== document.body && p !== root; p = p.parentElement) {\n if (getComputedStyle(p).overflowX !== \"visible\") return true;\n }\n return false;\n };\n const counts = (e) => {\n const r = e.getBoundingClientRect();\n if (r.width === 0 || r.height === 0 || r.right <= w + 0.5) return false;\n if (e.closest(\".sr,.sr-only,.visually-hidden,.skip\")) return false;\n if (e.closest(\"pre\") && e.tagName !== \"PRE\") return false;\n const s = getComputedStyle(e);\n if (s.visibility === \"hidden\" || s.display === \"none\") return false;\n if (s.position === \"fixed\" && r.left >= w) return false;\n return !inScroller(e);\n };\n const over = new Set([...document.querySelectorAll(\"body *\")].filter(counts));\n const past = [...over]\n .filter((e) => { for (let p = e.parentElement; p; p = p.parentElement) if (over.has(p)) return false; return true; })\n .map((e) => name(e) + \" right=\" + Math.round(e.getBoundingClientRect().right));\n const clipped = [...document.querySelectorAll(\"textarea\")]\n .filter((e) => { const s = getComputedStyle(e); return (s.overflowY === \"hidden\" || s.overflowY === \"clip\") && e.getBoundingClientRect().height > 0 && e.scrollHeight > e.clientHeight + 1; })\n .map((e) => name(e) + \" \" + e.scrollHeight + \">\" + e.clientHeight);\n return {\n innerWidth,\n scrollWidth: root.scrollWidth,\n height: Math.max(root.scrollHeight, document.body ? document.body.scrollHeight : 0),\n text: (document.body ? document.body.innerText : \"\").trim().length,\n past: past.slice(0, 8),\n clipped: clipped.slice(0, 8),\n };\n})()`;\n\n/** One check of a probe. */\nexport interface ProbeCheck {\n name: string;\n ok: boolean;\n detail?: string;\n}\n\n/**\n * This function wraps the code of a probe file into an expression. The code is the body of an async\n * function with these names:\n * - `check(name, ok, detail)` records a check,\n * - `wait(ms)` waits,\n * - `until(fn, ms)` waits until `fn()` gives a true value, at most `ms` (default 5000), and returns the value,\n * - `$(selector)` and `$$(selector)` find elements,\n * - `type(element, text)` writes the text into an input or a text area, with an `input` event,\n * - `click(element)` clicks an element, or the first element of a selector.\n * An exception stops the probe, and it counts as a failed check.\n */\nexport function probeExpression(code: string): string {\n return `(async () => {\n const __checks = [];\n const __text = (v) => { if (v === undefined) return undefined; if (typeof v === \"string\") return v; try { return JSON.stringify(v); } catch { return String(v); } };\n const check = (name, ok, detail) => { __checks.push({ name: String(name), ok: !!ok, ...(ok ? {} : { detail: __text(detail) }) }); return !!ok; };\n const wait = (ms) => new Promise((r) => setTimeout(r, ms));\n const until = async (fn, ms = 5000) => { const end = Date.now() + ms; for (;;) { const v = await fn(); if (v) return v; if (Date.now() > end) return v; await wait(50); } };\n const $ = (s) => document.querySelector(s);\n const $$ = (s) => [...document.querySelectorAll(s)];\n const __el = (e) => { const el = typeof e === \"string\" ? document.querySelector(e) : e; if (!el) throw new Error(\"no element: \" + e); return el; };\n const type = (e, text) => { const el = __el(e); el.focus(); el.value = text; el.dispatchEvent(new Event(\"input\", { bubbles: true })); el.dispatchEvent(new Event(\"change\", { bubbles: true })); };\n const click = (e) => __el(e).click();\n try {\n await (async () => {\n${code}\n })();\n } catch (e) {\n __checks.push({ name: \"the probe runs to its end\", ok: false, detail: String((e && e.stack) || e) });\n }\n return __checks;\n})()`;\n}\n","/**\n * A static file server for the `check` command. It serves a built site folder at the path of the\n * site home, as GitHub Pages does. Thus the links of the site work as on the live site.\n */\n\nimport { createReadStream, existsSync, statSync } from \"node:fs\";\nimport { createServer, type Server } from \"node:http\";\nimport { extname, join, normalize, resolve, sep } from \"node:path\";\n\nconst TYPES: Record<string, string> = {\n \".html\": \"text/html; charset=utf-8\",\n \".js\": \"text/javascript; charset=utf-8\",\n \".mjs\": \"text/javascript; charset=utf-8\",\n \".css\": \"text/css; charset=utf-8\",\n \".json\": \"application/json; charset=utf-8\",\n \".svg\": \"image/svg+xml\",\n \".png\": \"image/png\",\n \".jpg\": \"image/jpeg\",\n \".jpeg\": \"image/jpeg\",\n \".gif\": \"image/gif\",\n \".webp\": \"image/webp\",\n \".avif\": \"image/avif\",\n \".ico\": \"image/x-icon\",\n \".woff\": \"font/woff\",\n \".woff2\": \"font/woff2\",\n \".ttf\": \"font/ttf\",\n \".otf\": \"font/otf\",\n \".wasm\": \"application/wasm\",\n \".txt\": \"text/plain; charset=utf-8\",\n \".md\": \"text/markdown; charset=utf-8\",\n \".xml\": \"application/xml\",\n \".webmanifest\": \"application/manifest+json\",\n \".map\": \"application/json; charset=utf-8\",\n};\n\n/**\n * This function maps the path of a request to a file of the folder, as GitHub Pages does. A folder\n * gives its `index.html`. For a path with no extension, the function also tries `<path>.html`.\n *\n * @returns the absolute file, or undefined when the path is outside the base or the file is missing\n */\nexport function resolveFile(root: string, base: string, pathname: string): string | undefined {\n let decoded: string;\n try {\n decoded = decodeURIComponent(pathname);\n } catch {\n return undefined;\n }\n const home = base.endsWith(\"/\") ? base : `${base}/`;\n if (decoded === home.slice(0, -1)) decoded = home;\n if (!decoded.startsWith(home)) return undefined;\n const top = resolve(root);\n const file = normalize(join(top, decoded.slice(home.length)));\n if (file !== top && !file.startsWith(top + sep)) return undefined;\n const candidates = [file, join(file, \"index.html\"), `${file}.html`];\n return candidates.find((candidate) => existsSync(candidate) && statSync(candidate).isFile());\n}\n\n/** A started server. */\nexport interface StaticServer {\n /** The URL of the site home, for example `http://127.0.0.1:50123/client/`. */\n url: string;\n close(): Promise<void>;\n}\n\n/**\n * This function serves the folder at `base` on a free port of 127.0.0.1. A missing file gives the\n * status 404 with the `404.html` of the folder, when it has one.\n */\nexport async function serve(root: string, base: string): Promise<StaticServer> {\n const server: Server = createServer((request, response) => {\n const pathname = new URL(request.url ?? \"/\", \"http://localhost\").pathname;\n const home = base.endsWith(\"/\") ? base : `${base}/`;\n if (pathname === home.slice(0, -1) && home !== \"/\") {\n response.writeHead(301, { location: home }).end();\n return;\n }\n const file = resolveFile(root, base, pathname);\n const missing = join(resolve(root), \"404.html\");\n const send = file ?? (existsSync(missing) ? missing : undefined);\n if (send === undefined) {\n response.writeHead(404, { \"content-type\": \"text/plain; charset=utf-8\" }).end(`404: ${pathname}\\n`);\n return;\n }\n response.writeHead(file ? 200 : 404, { \"content-type\": TYPES[extname(send).toLowerCase()] ?? \"application/octet-stream\", \"cache-control\": \"no-store\" });\n createReadStream(send).pipe(response);\n });\n await new Promise<void>((done, fail) => {\n server.once(\"error\", fail);\n server.listen(0, \"127.0.0.1\", () => done());\n });\n const address = server.address();\n if (address === null || typeof address === \"string\") throw new Error(\"the server has no port\");\n return {\n url: `http://127.0.0.1:${address.port}${base.endsWith(\"/\") ? base : `${base}/`}`,\n close: () => new Promise((done) => server.close(() => done())),\n };\n}\n","/**\n * The `site-pages check` command. It opens the pages of a built site (or of a live URL) in a\n * headless Chromium at phone and desktop widths, in the light and the dark scheme.\n *\n * A view fails when the page is wider than the screen or an element goes past the right edge. It\n * also fails when a text area hides its text or the page shows no text. A console error, an\n * exception and a failed request of the site also fail it. A script that does not load and a failed check of the probe\n * fail it too. The command\n * writes a screenshot of each view.\n */\n\nimport { appendFileSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { isAbsolute, join, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { findBrowser, launch, type Page } from \"./browser.ts\";\nimport { MEASURE, probeExpression, type Measure, type ProbeCheck } from \"./measure.ts\";\nimport { probeScript, TYPESCRIPT_PROBE } from \"./probe.ts\";\nimport { serve } from \"./serve.ts\";\n\n/** The options of `checkSite`. */\nexport interface CheckOptions {\n /** The built site folder. Give `out` or `url`. */\n out?: string | undefined;\n /** The path of the site home, for `out`, for example `/client/`. */\n base?: string | undefined;\n /** The URL of a live site home. Give `out` or `url`. */\n url?: string | undefined;\n /** The pages, from the site home, for example `/` and `/releases/`. */\n pages: readonly string[];\n /** The widths in CSS pixels. A width under 768 is a phone. */\n widths: readonly number[];\n /** The color schemes. */\n schemes: readonly (\"light\" | \"dark\")[];\n /** The code of a probe: the body of an async function (see `probeExpression`). It runs on the first page, in the light scheme, at each width. */\n probe?: string | undefined;\n /** The folder for the screenshots, `report.json` and `summary.md`. */\n shots?: string | undefined;\n /** The browser executable. */\n browser?: string | undefined;\n /** The time to wait after the load event, for the scripts of the page. */\n settleMs: number;\n /** The time limit of a page load. */\n timeoutMs: number;\n log?: ((line: string) => void) | undefined;\n}\n\n/** The result of one page at one width and scheme. */\nexport interface ViewResult {\n page: string;\n width: number;\n scheme: \"light\" | \"dark\";\n ok: boolean;\n /** What failed. */\n problems: string[];\n measure?: Measure | undefined;\n probe?: ProbeCheck[] | undefined;\n /** The file of the screenshot. */\n shot?: string | undefined;\n}\n\n/** The result of `checkSite`. */\nexport interface CheckResult {\n ok: boolean;\n url: string;\n browser: string;\n views: ViewResult[];\n}\n\n/** This function gives the file name part of a page: `/` is `home`, `/releases/` is `releases`. */\nexport function pageSlug(page: string): string {\n const slug = page.replace(/^\\/+|\\/+$/g, \"\").replace(/[^A-Za-z0-9._-]+/g, \"_\");\n return slug === \"\" ? \"home\" : slug;\n}\n\n/**\n * This function checks the site. It starts one browser and, for `out`, one server, and stops both at\n * the end.\n *\n * @throws Error when there is no browser, or the browser does not start\n */\nexport async function checkSite(options: CheckOptions): Promise<CheckResult> {\n const log = options.log ?? (() => {});\n const executable = findBrowser(options.browser);\n if (executable === undefined) throw new Error(\"no Chromium browser was found: give --browser, set SITE_CHECK_BROWSER, or install the Chromium of Playwright\");\n if (options.pages.length === 0) throw new Error(\"no page to check\");\n const server = options.out !== undefined ? await serve(options.out, options.base ?? \"/\") : undefined;\n const home = server?.url ?? options.url;\n if (home === undefined) throw new Error(\"give out or url\");\n const homeUrl = new URL(home.endsWith(\"/\") ? home : `${home}/`);\n const browser = await launch(executable, options.timeoutMs);\n const views: ViewResult[] = [];\n try {\n const { page } = browser;\n const events = watch(page, homeUrl.origin);\n await Promise.all([page.send(\"Page.enable\"), page.send(\"Runtime.enable\"), page.send(\"Network.enable\")]);\n await page.send(\"Page.addScriptToEvaluateOnNewDocument\", { source: LOAD_WATCH });\n if (options.shots) mkdirSync(options.shots, { recursive: true });\n for (const [index, path] of options.pages.entries()) {\n const target = new URL(path.replace(/^\\/+/, \"\"), homeUrl).href;\n for (const width of options.widths) {\n for (const scheme of options.schemes) {\n const withProbe = options.probe !== undefined && index === 0 && scheme === options.schemes[0];\n const view = await checkView(page, events, { target, path, width, scheme, withProbe, options });\n views.push(view);\n log(`${view.ok ? \"PASS\" : \"FAIL\"} ${path} ${width} ${scheme}${view.measure ? ` scrollWidth=${view.measure.scrollWidth} innerWidth=${view.measure.innerWidth}` : \"\"}${view.probe ? ` probe ${view.probe.filter((c) => c.ok).length}/${view.probe.length}` : \"\"}${view.problems.length > 0 ? `\\n - ${view.problems.join(\"\\n - \")}` : \"\"}`);\n }\n }\n }\n } finally {\n await browser.close();\n await server?.close();\n }\n const result: CheckResult = { ok: views.length > 0 && views.every((view) => view.ok), url: homeUrl.href, browser: executable, views };\n if (options.shots) {\n writeFileSync(join(options.shots, \"report.json\"), `${JSON.stringify(result, null, 2)}\\n`);\n writeFileSync(join(options.shots, \"summary.md\"), summary(result));\n }\n return result;\n}\n\n/**\n * A script that each page starts before its own scripts. A script or a style sheet that does not load fires `error` on its\n * element. This script writes that event as a console error. Thus a module script whose imports do not load is a problem too.\n * Such a script throws no exception. Its failed request can go to another origin, for example `node:perf_hooks` in a page bundle.\n */\nexport const LOAD_WATCH = `addEventListener(\"error\", (event) => {\n const element = event.target;\n if (!(element instanceof HTMLScriptElement || element instanceof HTMLLinkElement)) return;\n console.error(\"failed to load \" + element.tagName.toLowerCase() + \": \" + (element.getAttribute(\"src\") ?? element.getAttribute(\"href\") ?? \"(inline)\"));\n}, true);`;\n\n/** The problems that the events of the page gave, since the last `reset`. */\ninterface Events {\n reset(): void;\n problems(): string[];\n}\n\nfunction watch(page: Page, origin: string): Events {\n let problems: string[] = [];\n const urls = new Map<string, string>();\n const own = (url: string) => {\n try {\n const parsed = new URL(url);\n // A browser asks for /favicon.ico on its own, also for a site under a path.\n return parsed.origin === origin && parsed.pathname !== \"/favicon.ico\";\n } catch {\n return false;\n }\n };\n page.on(\"Runtime.exceptionThrown\", (params) => {\n const details = params[\"exceptionDetails\"] as { text?: string; exception?: { description?: string } };\n problems.push(`exception: ${(details.exception?.description ?? details.text ?? \"\").split(\"\\n\")[0]}`);\n });\n page.on(\"Runtime.consoleAPICalled\", (params) => {\n if (params[\"type\"] !== \"error\" && params[\"type\"] !== \"assert\") return;\n const args = (params[\"args\"] as { value?: unknown; description?: string }[]) ?? [];\n problems.push(`console.error: ${args.map((arg) => String(arg.value ?? arg.description ?? \"\")).join(\" \").slice(0, 300)}`);\n });\n page.on(\"Network.requestWillBeSent\", (params) => {\n urls.set(String(params[\"requestId\"]), String((params[\"request\"] as { url: string }).url));\n });\n page.on(\"Network.responseReceived\", (params) => {\n const response = params[\"response\"] as { url: string; status: number };\n if (response.status >= 400 && own(response.url)) problems.push(`HTTP ${response.status}: ${response.url}`);\n });\n page.on(\"Network.loadingFailed\", (params) => {\n const url = urls.get(String(params[\"requestId\"])) ?? \"\";\n // A script of any origin counts: without it, the page does not work.\n if ((own(url) || params[\"type\"] === \"Script\") && params[\"canceled\"] !== true) problems.push(`request failed (${String(params[\"errorText\"])}): ${url}`);\n });\n return {\n reset: () => {\n problems = [];\n },\n problems: () => [...new Set(problems)],\n };\n}\n\ninterface ViewInput {\n target: string;\n path: string;\n width: number;\n scheme: \"light\" | \"dark\";\n withProbe: boolean;\n options: CheckOptions;\n}\n\nasync function checkView(page: Page, events: Events, input: ViewInput): Promise<ViewResult> {\n const { target, path, width, scheme, withProbe, options } = input;\n const view: ViewResult = { page: path, width, scheme, ok: false, problems: [] };\n try {\n await page.send(\"Emulation.setDeviceMetricsOverride\", { width, height: 900, deviceScaleFactor: 1, mobile: width < 768 });\n await page.send(\"Emulation.setEmulatedMedia\", { features: [{ name: \"prefers-color-scheme\", value: scheme }] });\n events.reset();\n const loaded = page.once(\"Page.loadEventFired\", options.timeoutMs);\n const navigation = (await page.send(\"Page.navigate\", { url: target })) as { errorText?: string };\n if (navigation.errorText) {\n loaded.catch(() => {});\n throw new Error(`the page did not open: ${navigation.errorText}`);\n }\n await loaded;\n await page.evaluate(\"document.fonts ? document.fonts.ready.then(() => true) : true\");\n await new Promise((done) => setTimeout(done, options.settleMs));\n const measure = await page.evaluate<Measure>(MEASURE);\n view.measure = measure;\n // The screen width, not innerWidth: a phone browser can zoom out a page that is too wide.\n if (measure.scrollWidth > width) view.problems.push(`the page is wider than the screen: ${measure.scrollWidth} > ${width}`);\n for (const past of measure.past) view.problems.push(`past the right edge: ${past}`);\n for (const clipped of measure.clipped) view.problems.push(`a text area hides its text: ${clipped}`);\n if (measure.text === 0) view.problems.push(\"the page shows no text\");\n if (options.shots) {\n const file = join(options.shots, `${pageSlug(path)}-${width}-${scheme}.png`);\n const height = Math.min(Math.max(measure.height, 1), 8000);\n const shot = (await page.send(\"Page.captureScreenshot\", { format: \"png\", captureBeyondViewport: true, clip: { x: 0, y: 0, width, height, scale: 1 } })) as { data: string };\n writeFileSync(file, Buffer.from(shot.data, \"base64\"));\n view.shot = file;\n }\n if (withProbe && options.probe !== undefined) {\n const checks = (await page.evaluate<ProbeCheck[] | undefined>(probeExpression(options.probe))) ?? [];\n view.probe = checks;\n if (checks.length === 0) view.problems.push(\"the probe made no check\");\n for (const check of checks.filter((entry) => !entry.ok)) view.problems.push(`probe: ${check.name}${check.detail ? ` (${check.detail})` : \"\"}`);\n }\n } catch (error) {\n view.problems.push(error instanceof Error ? error.message : String(error));\n }\n view.problems.push(...events.problems());\n view.ok = view.problems.length === 0;\n return view;\n}\n\n/** This function makes a text safe for a cell of a Markdown table. It escapes `\\`, `|`, `<` and `>`. It changes each new line to a space. */\nexport function cell(text: string): string {\n return text.replace(/\\\\/g, \"\\\\\\\\\").replace(/\\|/g, \"\\\\|\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\").replace(/\\r?\\n/g, \" \");\n}\n\n/** This function gives the Markdown summary of a result, for the job summary of a workflow. */\nexport function summary(result: CheckResult): string {\n const failed = result.views.filter((view) => !view.ok);\n const lines = [\n `### Site check: ${result.ok ? \"passed\" : \"failed\"}`,\n \"\",\n `${result.views.length - failed.length} of ${result.views.length} views passed, at ${result.url}.`,\n \"\",\n \"| Page | Width | Scheme | Result | Problems |\",\n \"| --- | ---: | --- | --- | --- |\",\n ...result.views.map(\n (view) =>\n `| \\`${view.page}\\` | ${view.width} | ${view.scheme} | ${view.ok ? \"pass\" : \"**fail**\"}${view.probe ? ` (probe ${view.probe.filter((c) => c.ok).length}/${view.probe.length})` : \"\"} | ${view.problems.map(cell).join(\"<br>\")} |`,\n ),\n \"\",\n ];\n return lines.join(\"\\n\");\n}\n\n/** The input and output of the CLI. */\nexport interface CheckIo {\n cwd: string;\n env: NodeJS.ProcessEnv;\n stdout: (text: string) => void;\n stderr: (text: string) => void;\n}\n\nexport const CHECK_HELP = `Usage: site-pages check (--out <dir> | --url <url>) [options]\n\nOpens the pages of the site in a headless Chromium at phone and desktop widths, in the light and\nthe dark scheme, and fails when a page is wider than the screen, an element goes past the right\nedge, a text area hides its text, a page shows no text, or on a console error, an exception, a\nfailed request of the site, a script that does not load or a failed check of the probe.\n\nOptions:\n --out <dir> The built site folder. The check serves it at --base.\n --url <url> The URL of a live site home, in place of --out\n --repo <owner/name> The GitHub repository, for the default base (default: $GITHUB_REPOSITORY)\n --base </name/> The path of the site home (default: \"/<name>/\", or \"/\" for <owner>.github.io)\n --pages <paths> The pages, from the site home, separated by commas (default: /)\n --widths <px> The widths, separated by commas (default: 360,400,1280)\n --schemes <list> light, dark or both (default: light,dark)\n --probe <file> A JavaScript file: the body of an async function with check(name, ok, detail),\n wait, until, $, $$, type and click. It runs on the first page, in the first\n scheme, at each width. A .ts, .mts or .cts file is TypeScript: the check\n removes its types and its line export {}.\n --shots <dir> The folder for the screenshots, report.json and summary.md\n --browser <file> The Chromium executable (default: $SITE_CHECK_BROWSER, the Chromium of\n Playwright, else Chrome or Edge)\n --settle <ms> The wait after the load event (default: 1500)\n --timeout <ms> The time limit of a page load (default: 30000)\n --help Shows this text\n\nWith $GITHUB_STEP_SUMMARY, the check adds its table to the job summary.\n`;\n\n/** This function runs the `check` command with its arguments, without the word `check`. */\nexport async function runCheckCli(argv: readonly string[], io: CheckIo): Promise<number> {\n let values: Record<string, string | boolean | undefined>;\n try {\n ({ values } = parseArgs({\n args: [...argv],\n allowPositionals: false,\n options: {\n out: { type: \"string\" },\n url: { type: \"string\" },\n repo: { type: \"string\" },\n base: { type: \"string\" },\n pages: { type: \"string\" },\n widths: { type: \"string\" },\n schemes: { type: \"string\" },\n probe: { type: \"string\" },\n shots: { type: \"string\" },\n browser: { type: \"string\" },\n settle: { type: \"string\" },\n timeout: { type: \"string\" },\n help: { type: \"boolean\" },\n },\n }));\n } catch (error) {\n io.stderr(`site-pages check: ${error instanceof Error ? error.message : String(error)}\\n\\n${CHECK_HELP}`);\n return 2;\n }\n if (values[\"help\"]) {\n io.stdout(CHECK_HELP);\n return 0;\n }\n const usage = (message: string) => {\n io.stderr(`site-pages check: ${message}\\n\\n${CHECK_HELP}`);\n return 2;\n };\n const text = (key: string) => (typeof values[key] === \"string\" ? (values[key] as string) : undefined);\n const list = (key: string, fallback: string) => (text(key) ?? fallback).split(\",\").map((entry) => entry.trim()).filter(Boolean);\n const out = text(\"out\");\n const url = text(\"url\");\n if ((out === undefined) === (url === undefined)) return usage(\"give --out or --url, not both\");\n const widths = list(\"widths\", \"360,400,1280\").map(Number);\n if (widths.length === 0 || widths.some((width) => !Number.isInteger(width) || width < 200 || width > 4000)) return usage(\"--widths must be whole numbers from 200 to 4000\");\n const schemes = list(\"schemes\", \"light,dark\");\n if (schemes.length === 0 || schemes.some((scheme) => scheme !== \"light\" && scheme !== \"dark\")) return usage(\"--schemes must be light, dark or both\");\n const pages = list(\"pages\", \"/\");\n if (pages.length === 0) return usage(\"--pages has no page\");\n // Git Bash changes a bare \"/\" into \"C:/Program Files/Git/\". A page is a path, with no scheme or drive.\n const notPath = pages.find((entry) => entry.includes(\":\") || entry.includes(\"\\\\\"));\n if (notPath !== undefined) return usage(`a page is a path from the site home, not \"${notPath}\" (in Git Bash, set MSYS_NO_PATHCONV=1)`);\n const settleMs = Number(text(\"settle\") ?? 1500);\n const timeoutMs = Number(text(\"timeout\") ?? 30000);\n if (!(settleMs >= 0) || !(timeoutMs > 0)) return usage(\"--settle and --timeout must be numbers of milliseconds\");\n let base = text(\"base\");\n if (out !== undefined && base === undefined) {\n const name = (text(\"repo\") ?? io.env[\"GITHUB_REPOSITORY\"] ?? \"\").split(\"/\")[1];\n if (!name) return usage(\"give --base, --repo or set GITHUB_REPOSITORY\");\n base = /\\.github\\.io$/i.test(name) ? \"/\" : `/${name}/`;\n }\n if (base !== undefined) base = `/${base.replace(/^\\/+|\\/+$/g, \"\")}/`.replace(/^\\/\\/$/, \"/\");\n const at = (file: string) => (isAbsolute(file) ? file : resolve(io.cwd, file));\n const probeFile = text(\"probe\");\n let probe: string | undefined;\n if (probeFile !== undefined) {\n try {\n probe = readFileSync(at(probeFile), \"utf8\");\n } catch (error) {\n return usage(`the probe file ${probeFile} cannot be read: ${error instanceof Error ? error.message : String(error)}`);\n }\n if (TYPESCRIPT_PROBE.test(probeFile)) {\n try {\n probe = probeScript(probe);\n } catch (error) {\n return usage(`the types of the probe file ${probeFile} cannot be removed: ${error instanceof Error ? error.message : String(error)}`);\n }\n }\n }\n const shots = text(\"shots\");\n const result = await checkSite({\n out: out === undefined ? undefined : at(out),\n base,\n url,\n pages,\n widths,\n schemes: schemes as (\"light\" | \"dark\")[],\n probe,\n shots: shots === undefined ? undefined : at(shots),\n browser: text(\"browser\"),\n settleMs,\n timeoutMs,\n log: (line) => io.stdout(`${line}\\n`),\n });\n const failed = result.views.filter((view) => !view.ok).length;\n io.stdout(`site-pages check: ${result.views.length - failed} of ${result.views.length} views passed (${result.browser}).\\n`);\n const step = io.env[\"GITHUB_STEP_SUMMARY\"];\n if (step) appendFileSync(step, summary(result));\n return result.ok ? 0 : 1;\n}\n","#!/usr/bin/env node\n// The bin `site-pages`. The work is in build.ts and check/check.ts, so a test can run the same CLI with its own fetch.\nimport { runCli } from \"./build.ts\";\nimport { runCheckCli } from \"./check/check.ts\";\n\nconst argv = process.argv.slice(2);\nconst io = {\n cwd: process.cwd(),\n env: process.env,\n stdout: (text: string) => process.stdout.write(text),\n stderr: (text: string) => process.stderr.write(text),\n};\n(argv[0] === \"check\" ? runCheckCli(argv.slice(1), io) : runCli(argv, io)).then(\n (code) => {\n process.exitCode = code;\n },\n (error: unknown) => {\n process.stderr.write(`site-pages: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}\\n`);\n process.exitCode = 1;\n },\n);\n"],"mappings":"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"}
package/build/index.d.ts CHANGED
@@ -648,6 +648,14 @@ export declare function classCounts(items: readonly BoardItem[]): Record<StatusC
648
648
  export declare const STATUS_SCRIPT: string;
649
649
  /** This function renders the complete status page from the data of `status.json`. */
650
650
  export declare function renderStatusPage(data: StatusBoardData, options: PageOptions): string;
651
+ /** A probe file in TypeScript: `.ts`, `.mts` or `.cts`. */
652
+ export declare const TYPESCRIPT_PROBE: RegExp;
653
+ /**
654
+ * This function gives the JavaScript of a probe in TypeScript. It removes the types, and the line `export {};` that makes the
655
+ * file a module for the typecheck. Each line stays at its position, so the line of an error is the line of the source. Syntax
656
+ * that is not only types (an `enum`, a `namespace`) causes an error.
657
+ */
658
+ export declare function probeScript(source: string): string;
651
659
  /** An error in the command line. The CLI shows the help and exits with code 2. */
652
660
  export declare class UsageError extends Error {}
653
661
  /** The options of `build`. */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/data/types.ts","../src/data/versions.ts","../src/data/changelog.ts","../src/data/github.ts","../src/data/npm.ts","../src/data/git.ts","../src/data/glob.ts","../src/data/releases.ts","../src/data/status.ts","../src/render/html.ts","../src/render/dates.ts","../src/render/theme.ts","../src/render/timeline.ts","../src/render/releases.ts","../src/render/status.ts","../src/build.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/data/types.ts","../src/data/versions.ts","../src/data/changelog.ts","../src/data/github.ts","../src/data/npm.ts","../src/data/git.ts","../src/data/glob.ts","../src/data/releases.ts","../src/data/status.ts","../src/render/html.ts","../src/render/dates.ts","../src/render/theme.ts","../src/render/timeline.ts","../src/render/releases.ts","../src/render/status.ts","../src/check/probe.ts","../src/build.ts"],"mappings":"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"}
package/build/index.js CHANGED
@@ -1 +1 @@
1
- export { b as BASE_CSS, V as DEFAULT_CHANGELOGS, et as GITHUB_API, tt as GITHUB_GRAPHQL, t as HELP, Q as NPM_REGISTRY, k as OPEN_CLASSES, p as RELEASES_SCRIPT, H as ReleaseDataError, A as RoadmapParseError, j as STATUS_CLASSES, o as STATUS_SCRIPT, n as UsageError, r as build, M as buildStatusBoard, nt as checkStateOf, s as classCounts, lt as compareVersions, S as dayRange, E as escapeHtml, at as firstSentence, q as gitTagDates, rt as githubOpenWork, it as githubReleases, K as globFiles, J as headCommit, ot as headingAnchor, Y as headingDate, D as inlineMarkdown, X as isShallow, ut as kindOf, g as laneCenter, N as linksOf, C as longDate, P as markdownTables, U as mergeReleases, $ as npmPublishTimes, _ as oldestFirst, c as openGroups, Z as originRepository, x as pageShell, i as parseBuildArgs, st as parseChangelog, F as parseRoadmap, dt as parseVersion, I as plainText, W as readChangelogs, G as readReleases, L as readStatusBoard, ct as releaseBodyEntries, v as releaseSummary, m as releasesLead, h as renderReleasesPage, l as renderStatusPage, R as roadmapItems, a as runCli, O as safeUrl, u as sectionsOf, w as shortDate, d as slugOf, z as splitRow, B as statusClassOf, f as statusLead, y as timelineLayout, T as utcDay, ft as versionOfTag } from "./build-CD2wc7Yl.js";
1
+ export { S as BASE_CSS, U as DEFAULT_CHANGELOGS, nt as GITHUB_API, rt as GITHUB_GRAPHQL, t as HELP, et as NPM_REGISTRY, j as OPEN_CLASSES, h as RELEASES_SCRIPT, W as ReleaseDataError, M as RoadmapParseError, N as STATUS_CLASSES, c as STATUS_SCRIPT, o as TYPESCRIPT_PROBE, n as UsageError, r as build, P as buildStatusBoard, it as checkStateOf, l as classCounts, dt as compareVersions, w as dayRange, O as escapeHtml, st as firstSentence, Y as gitTagDates, at as githubOpenWork, ot as githubReleases, J as globFiles, X as headCommit, ct as headingAnchor, Z as headingDate, k as inlineMarkdown, Q as isShallow, ft as kindOf, v as laneCenter, F as linksOf, T as longDate, I as markdownTables, G as mergeReleases, tt as npmPublishTimes, y as oldestFirst, u as openGroups, $ as originRepository, C as pageShell, i as parseBuildArgs, lt as parseChangelog, L as parseRoadmap, pt as parseVersion, R as plainText, s as probeScript, K as readChangelogs, q as readReleases, z as readStatusBoard, ut as releaseBodyEntries, b as releaseSummary, g as releasesLead, _ as renderReleasesPage, d as renderStatusPage, B as roadmapItems, a as runCli, A as safeUrl, f as sectionsOf, E as shortDate, p as slugOf, V as splitRow, H as statusClassOf, m as statusLead, x as timelineLayout, D as utcDay, mt as versionOfTag } from "./build-xJqNIzdO.js";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/site-pages",
4
- "version": "0.1.8",
4
+ "version": "0.1.9",
5
5
  "description": "A release timeline page and a live status page for the site of a GitHub repository: JSON data and standalone HTML, made at deploy time.",
6
6
  "keywords": [
7
7
  "github-pages",
@@ -26,6 +26,14 @@
26
26
  "author": "Mark Russell (https://github.com/mark1russell7)",
27
27
  "type": "module",
28
28
  "main": "./build/index.js",
29
+ "exports": {
30
+ ".": {
31
+ "types": "./build/index.d.ts",
32
+ "import": "./build/index.js"
33
+ },
34
+ "./scroll-cue.css": "./styles/scroll-cue.css",
35
+ "./package.json": "./package.json"
36
+ },
29
37
  "bin": {
30
38
  "site-pages": "./build/cli.js"
31
39
  },
@@ -52,13 +60,5 @@
52
60
  "test:watch": "vitest",
53
61
  "typecheck": "tsc -p tsconfig.json && tsc -p tsconfig.test.json"
54
62
  },
55
- "types": "./build/index.d.ts",
56
- "exports": {
57
- ".": {
58
- "types": "./build/index.d.ts",
59
- "import": "./build/index.js"
60
- },
61
- "./scroll-cue.css": "./styles/scroll-cue.css",
62
- "./package.json": "./package.json"
63
- }
63
+ "types": "./build/index.d.ts"
64
64
  }