@hawkeyexl/manni 0.0.0-bootstrap.0 → 0.2.0
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/LICENSE +21 -0
- package/README.md +178 -0
- package/dist/chunk-2OALUJV2.js +10820 -0
- package/dist/chunk-2OALUJV2.js.map +1 -0
- package/dist/chunk-OXH2ZM7E.js +1050 -0
- package/dist/chunk-OXH2ZM7E.js.map +1 -0
- package/dist/cli.d.ts +17 -0
- package/dist/cli.js +914 -0
- package/dist/cli.js.map +1 -0
- package/dist/docmeta.d.ts +2 -0
- package/dist/docmeta.js +10 -0
- package/dist/docmeta.js.map +1 -0
- package/dist/index.d.ts +1623 -0
- package/dist/index.js +116 -0
- package/dist/index.js.map +1 -0
- package/package.json +104 -3
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/a11y/cli.ts","../src/shared/severity.ts","../src/a11y/types.ts","../src/a11y/core/url.ts","../src/a11y/core/crawl.ts","../src/a11y/core/sitemap.ts","../src/a11y/commands/check.ts","../src/a11y/core/analyzer.ts","../src/a11y/core/config.ts","../src/a11y/reporters/github.ts","../src/a11y/reporters/json.ts","../src/a11y/reporters/pretty.ts","../src/a11y/reporters/index.ts","../src/a11y/reporters/progress.ts"],"sourcesContent":["/**\n * The `manni` CLI: one bin, one subcommand per tool in the family.\n *\n * Each tool builds its own commander program and is mounted here under its\n * name, so `manni meta validate …` is the metadata tool's `validate` with\n * nothing in between. The umbrella owns only what is common to all of them:\n * the name, the version, and the exit-code contract in `runProgram`.\n *\n * Tools land here one at a time, on their own branches; until one merges its\n * subcommand does not exist.\n */\nimport { Command } from \"commander\";\nimport pkg from \"../package.json\" with { type: \"json\" };\nimport { buildProgram as buildA11y } from \"./a11y/cli.js\";\nimport { buildProgram as buildMeta } from \"./meta/cli.js\";\nimport { runIfMain } from \"./shared/run.js\";\n\nexport function buildProgram(): Command {\n const meta = buildMeta()\n .name(\"meta\")\n .description(\n \"Validate, read, query and fill document metadata against JSON Schema\",\n );\n const metaCommands = new Set(meta.commands.map((c) => c.name()));\n\n const program = new Command();\n program\n .name(\"manni\")\n .description(\"Tools for documentation that is meant to be checked.\")\n .version(pkg.version, \"-V, --version\")\n // A pointer, not the whole help screen. Commander appends this after every\n // usage error, and the message that precedes it already names the problem.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before `addCommand`, which copies the exit callback into the\n // mounted program by value. See the same note in ./meta/cli.ts.\n .exitOverride()\n .configureOutput({\n outputError: (str, write) => {\n write(str);\n // `manni validate …` is the most likely thing a docmeta user types\n // first. Commander's \"unknown command\" is correct and unhelpful; say\n // where the command went.\n const m = /unknown command '([^']+)'/.exec(str);\n const name = m?.[1];\n if (name !== undefined && metaCommands.has(name)) {\n write(\n `(\\`${name}\\` is a metadata command: try \\`manni meta ${name}\\`)\\n`,\n );\n }\n },\n });\n\n program.addCommand(meta);\n program.addCommand(\n buildA11y()\n .name(\"a11y\")\n .description(\n \"Crawl a site and check every page for accessibility violations with axe-core\",\n ),\n );\n return program;\n}\n\nrunIfMain(import.meta.url, buildProgram);\n","/**\n * The a11y tool's CLI. A thin commander wrapper over `runCheck`, following\n * clig.dev the way meta's does: primary output to stdout, diagnostics to\n * stderr, color only on a TTY (never under NO_COLOR/--no-color), and the\n * exit codes 0 ok, 1 findings, 2 operational/usage.\n *\n * Every flag is validated here and turned into an `A11yError` before the\n * browser is asked to launch, so a typo costs a message and not a launch.\n */\nimport { Command } from \"commander\";\nimport pkg from \"../../package.json\" with { type: \"json\" };\nimport { shouldColor } from \"../shared/color.js\";\nimport { fail } from \"../shared/run.js\";\nimport { CHECK_DEFAULTS, runCheck } from \"./commands/check.js\";\nimport { createPlaywrightAnalyzer } from \"./core/analyzer.js\";\nimport { loadA11yConfig, type LoadedA11yConfig } from \"./core/config.js\";\nimport { A11Y_FORMAT_LIST, isA11yFormat, render } from \"./reporters/index.js\";\nimport { CLEAR_LINE, createProgressReporter } from \"./reporters/progress.js\";\nimport {\n A11yError,\n SEVERITY_LIST,\n isSeverity,\n type Severity,\n type ProgressListener,\n} from \"./types.js\";\n\n/** `--tags <list>`: commas separate, whitespace around them is trimmed, empty items are dropped. */\nfunction splitList(value: string): string[] {\n return value\n .split(\",\")\n .map((s) => s.trim())\n .filter(Boolean);\n}\n\n/**\n * Whether to paint what goes to `stream`. The report and the progress line\n * are decided separately, since stdout may be a pipe while stderr is still\n * the terminal (`-f json | jq`), and the other way round.\n */\nfunction resolveColor(program: Command, stream: NodeJS.WriteStream): boolean {\n // commander maps --no-color to opts.color === false.\n const noColor = program.opts().color === false;\n // `isTTY` is undefined off a terminal, never false; `shouldColor` treats a\n // missing one as \"not a terminal\".\n return shouldColor({ noColor, isTTY: stream.isTTY });\n}\n\ninterface Progress {\n /** Hears the run's events; `undefined` keeps the run silent. */\n listener: ProgressListener | undefined;\n /**\n * Erase the status line. On a terminal it is rewritten in place, and a run\n * that dies mid-crawl (no browser, a seed that will not load) would leave\n * it there for the error to land on. A no-op everywhere else.\n */\n clear: () => void;\n}\n\n/**\n * `--progress` and `--no-progress` decide; with neither, progress is on\n * exactly when stderr is a terminal, so a CI log stays as it was.\n */\nfunction resolveProgress(program: Command, flag: boolean | undefined): Progress {\n // @types/node says boolean; off a terminal it is undefined (see resolveColor).\n const tty = (process.stderr.isTTY as boolean | undefined) ?? false;\n const silent: Progress = { listener: undefined, clear: () => undefined };\n if (!(flag ?? tty)) return silent;\n const listener = createProgressReporter({\n stream: process.stderr,\n color: resolveColor(program, process.stderr),\n tty,\n });\n if (!tty) return { listener, clear: silent.clear };\n return {\n listener,\n clear: () => {\n process.stderr.write(CLEAR_LINE);\n },\n };\n}\n\n/**\n * A positive integer flag, in canonical form. Anything else is a usage error:\n * `0`, `-3`, `2.5`, `many`, and `01`, since a leading zero is not how anyone\n * writes a page count and would read as an octal literal elsewhere.\n * Exported for its unit test only.\n */\nexport function positiveInteger(value: string, flag: string): number {\n if (!/^[1-9]\\d*$/.test(value)) {\n throw new A11yError(`${flag} must be an integer >= 1.`);\n }\n return Number(value);\n}\n\nfunction assertSeverity(value: string): Severity {\n if (!isSeverity(value)) {\n throw new A11yError(`Unknown --severity \"${value}\". Use ${SEVERITY_LIST}.`);\n }\n return value;\n}\n\ninterface CheckCliOptions {\n /** `-f, --format` (default \"pretty\"). */\n format: string;\n /** `--no-crawl` → false. */\n crawl: boolean;\n /** `--max-pages <n>`, parsed to int here. No default: absent means no cap. */\n maxPages?: string;\n /** `--tags <list>`, split on \",\" here (same helper shape as meta's --ext). */\n tags?: string;\n /** `--severity <level>`. */\n severity: string;\n /** `--timeout <ms>`, parsed to int here. */\n timeout: string;\n /** `-q, --quiet`. */\n quiet?: boolean;\n /** `--progress` → true, `--no-progress` → false, neither → undefined (auto). */\n progress?: boolean;\n /** `-c <path>` | `--no-config` → false. */\n config?: string | false;\n}\n\n/** Commander program named \"a11y\"; the umbrella mounts it. No entry point. */\nexport function buildProgram(): Command {\n const program = new Command();\n program\n .name(\"a11y\")\n .description(\"Crawl a site and check every page for accessibility violations with axe-core\")\n .version(pkg.version, \"-V, --version\")\n .option(\"--no-color\", \"disable colored output\")\n // A pointer, not the whole help screen; the message before it already\n // names the offending flag.\n .showHelpAfterError(\"(add --help for usage)\")\n // MUST come before the `.command()` call below. `copyInheritedSettings`\n // copies `_exitCallback` **by value** at subcommand-creation time, so an\n // `exitOverride()` installed afterwards leaves the subcommand calling\n // `process.exit(1)` while the program-level case looks fixed.\n .exitOverride();\n\n program\n .command(\"check\")\n .description(\"Crawl from the given URLs and check every page with axe-core\")\n .argument(\n \"[urls...]\",\n \"http(s) seed URLs; falls back to a11y.urls in manni.config.yaml\",\n )\n .option(\"-f, --format <format>\", `output: ${A11Y_FORMAT_LIST}`, \"pretty\")\n .option(\"--no-crawl\", \"check exactly the given URLs: no sitemap, no link following\")\n // No commander default on purpose: the built-in behaviour is to check\n // everything discovered, and \"no cap\" is not a value commander could hold.\n .option(\n \"--max-pages <n>\",\n \"cap on pages checked; the rest are reported as skipped (default: no cap)\",\n )\n .option(\"--tags <list>\", \"comma-separated axe tags to restrict the rules to\")\n .option(\n \"--severity <level>\",\n `minimum severity reported: ${SEVERITY_LIST}`,\n CHECK_DEFAULTS.severity,\n )\n .option(\n \"--timeout <ms>\",\n \"per-page navigation timeout in milliseconds\",\n String(CHECK_DEFAULTS.timeout),\n )\n .option(\"-q, --quiet\", \"in pretty output, hide pages with no violations\")\n // `--progress` first, so that adding `--no-progress` leaves the default\n // undefined (auto) instead of commander's `true` for a lone negation.\n .option(\"--progress\", \"report progress on stderr (default: only on a terminal)\")\n .option(\"--no-progress\", \"never report progress\")\n .option(\"-c, --config <path>\", \"path to a manni config file\")\n .option(\"--no-config\", \"ignore any discovered config file\")\n .action(async (urls: string[], options: CheckCliOptions, command: Command) => {\n // Settled once the flags are validated; until then there is no line to clear.\n let clearProgress = (): void => undefined;\n try {\n // A value commander filled in from the option's default yields to the\n // config file; one the user typed wins over it. Same three-way\n // precedence as meta: CLI flag > config key > default.\n const typed = (name: string): boolean =>\n command.getOptionValueSource(name) === \"cli\";\n\n const format = options.format;\n if (!isA11yFormat(format)) {\n throw new A11yError(`Unknown --format \"${format}\". Use ${A11Y_FORMAT_LIST}.`);\n }\n const severity = assertSeverity(options.severity);\n const maxPages =\n options.maxPages === undefined\n ? undefined\n : positiveInteger(options.maxPages, \"--max-pages\");\n const timeout = positiveInteger(options.timeout, \"--timeout\");\n\n const loaded: LoadedA11yConfig =\n options.config === false\n ? { config: {}, source: null }\n : await loadA11yConfig(process.cwd(), options.config);\n const cfg = loaded.config;\n\n const parent = command.parent ?? command;\n const progress = resolveProgress(parent, options.progress);\n clearProgress = progress.clear;\n\n const run = await runCheck(\n {\n urls: urls.length > 0 ? urls : (cfg.urls ?? []),\n crawl: typed(\"crawl\") ? options.crawl : (cfg.crawl ?? CHECK_DEFAULTS.crawl),\n // Typed flag > config key > no cap. There is no default to fall to.\n maxPages: maxPages ?? cfg.maxPages,\n tags:\n options.tags !== undefined\n ? splitList(options.tags)\n : (cfg.tags ?? CHECK_DEFAULTS.tags),\n severity: typed(\"severity\") ? severity : (cfg.severity ?? CHECK_DEFAULTS.severity),\n timeout: typed(\"timeout\") ? timeout : (cfg.timeout ?? CHECK_DEFAULTS.timeout),\n },\n { analyzer: createPlaywrightAnalyzer(), onProgress: progress.listener },\n );\n\n const color = resolveColor(parent, process.stdout);\n const text = render(format, run, { color, quiet: Boolean(options.quiet) });\n // Only `github` may say nothing on a clean run; every other format\n // owes its envelope even when it is empty.\n if (text.length > 0 || format !== \"github\") {\n process.stdout.write(`${text}\\n`);\n }\n process.exitCode = run.summary.failed > 0 ? 1 : 0;\n } catch (err) {\n clearProgress();\n fail(err);\n }\n });\n\n return program;\n}\n\n","/**\n * The one severity scale every manni tool speaks. Least to most severe.\n *\n * Three values, chosen to match the sinks every tool writes to and the\n * linters that sit beside it. GitHub annotations are `error`, `warning` and\n * `notice`; so are ESLint's and Vale's levels, and pa11y's. A flag or config\n * key that two domains both have carries the same name and the same values,\n * and this is where the values for `severity` are defined once.\n *\n * A domain whose source speaks another scale maps onto this one and keeps\n * the source's value in a field of its own, so nothing is lost for lookup.\n * a11y is the first case: axe reports four impacts, the analyzer folds them\n * onto these three, and each finding still carries axe's word as `impact`.\n */\nexport const SEVERITIES = [\"notice\", \"warning\", \"error\"] as const;\nexport type Severity = (typeof SEVERITIES)[number];\n\n/** The list the way a usage message spells it: `notice | warning | error`. */\nexport const SEVERITY_LIST: string = SEVERITIES.join(\" | \");\n\nexport function isSeverity(value: string): value is Severity {\n return (SEVERITIES as readonly string[]).includes(value);\n}\n\n/** `true` when `severity` is at or above `min`. */\nexport function meetsSeverity(severity: Severity, min: Severity): boolean {\n return SEVERITIES.indexOf(severity) >= SEVERITIES.indexOf(min);\n}\n","/**\n * The shapes the a11y tool produces and the error it throws.\n *\n * Everything downstream of the browser — the crawl, the check core, the\n * reporters — speaks in these types, so the analyzer is the only module that\n * knows axe's own result shape.\n */\nimport { ToolError } from \"../shared/errors.js\";\nimport type { Severity } from \"../shared/severity.js\";\n\n/**\n * The severity scale is the family's, not a11y's. It is re-exported here so\n * the tool's own modules and tests have one import for everything they speak.\n */\nexport {\n SEVERITIES,\n SEVERITY_LIST,\n isSeverity,\n meetsSeverity,\n type Severity,\n} from \"../shared/severity.js\";\n\n/** Operational/usage failure of the a11y tool: one line on stderr, exit 2. */\nexport class A11yError extends ToolError {\n constructor(message: string) {\n super(message);\n this.name = \"A11yError\";\n }\n}\n\n/**\n * axe's own scale, which it calls impact. Least to most severe. The analyzer\n * maps these onto the family `Severity` (`severityOf`) and keeps the original\n * on the violation as `impact`.\n */\nexport const AXE_IMPACTS = [\"minor\", \"moderate\", \"serious\", \"critical\"] as const;\nexport type AxeImpact = (typeof AXE_IMPACTS)[number];\n\nexport function isAxeImpact(value: string): value is AxeImpact {\n return (AXE_IMPACTS as readonly string[]).includes(value);\n}\n\nexport interface ViolationNode {\n /** axe's CSS selector path to the element (joined `target`). */\n target: string;\n /** The element's outer HTML, as axe reports it (truncated to 200 chars in pretty output only). */\n html: string;\n /** axe's failureSummary: what to fix, in prose. */\n summary: string;\n}\n\nexport interface Violation {\n /** axe rule id, e.g. \"image-alt\". */\n id: string;\n /** The family level, mapped from `impact`. What the floor and the reporters use. */\n severity: Severity;\n /**\n * axe's own value, kept for lookup against Deque's rule pages and the axe\n * DevTools report a team already reads. An unknown or `null` impact is\n * recorded as `\"minor\"`.\n */\n impact: AxeImpact;\n /** Short rule description, e.g. \"Images must have alternate text\". */\n help: string;\n /** Deque University rule page. */\n helpUrl: string;\n /** axe tags, e.g. [\"cat.text-alternatives\", \"wcag2a\", \"wcag111\"]. */\n tags: string[];\n nodes: ViolationNode[];\n}\n\nexport interface PageResult {\n /** Normalized URL that was checked. */\n url: string;\n /** How the URL entered the run. */\n source: \"seed\" | \"sitemap\" | \"link\";\n /** Violations at or above the severity floor. Empty when `error` is set. */\n violations: Violation[];\n /** Count of axe rules that passed on this page. */\n passes: number;\n /** Count of rules axe could not decide (reported, never counted as failures). */\n incomplete: number;\n /**\n * round(100 × passes ÷ (passes + violations.length)), the share of applicable\n * axe rules that passed after severity filtering. Not a Lighthouse score.\n * `null` when the page did not load, or when no rule applied.\n */\n score: number | null;\n /** Set when the page could not be loaded or analyzed; the page counts as failed. */\n error?: string;\n}\n\nexport interface CheckSummary {\n /** Distinct URLs that entered the frontier (seeds + sitemap + links). */\n discovered: number;\n /** Pages actually analyzed. */\n checked: number;\n /** Discovered but not checked because the `maxPages` cap was reached; `0` without a cap. */\n skipped: number;\n /**\n * Discovered, then dropped unloaded because the browser had already landed\n * on the same page under another spelling (a redirect target). Neither\n * checked nor skipped: `checked + skipped + duplicates === discovered`.\n */\n duplicates: number;\n /** Pages with ≥1 remaining violation or an `error`. Drives exit 1. */\n failed: number;\n /** Total remaining violations across pages (rules, not nodes). */\n violations: number;\n /** Violations by family severity, always all three keys, zero-filled. */\n bySeverity: Record<Severity, number>;\n /** The sitemap URL that supplied pages, or `null` if none was used. */\n sitemap: string | null;\n /**\n * Whether the run discovered pages beyond the seeds (sitemap and same-host\n * links). `false` under `--no-crawl`, where `sitemap` is always `null` and\n * no link was followed.\n */\n crawl: boolean;\n}\n\nexport interface CheckRun {\n results: PageResult[];\n summary: CheckSummary;\n}\n\n/**\n * What a run says while it is still running. The crawl emits these in order\n * (`browser`, then `page`/`checked` per page, then `done`); the check core\n * adds `sitemap` before them when it crawls. A listener is optional, and\n * nothing is emitted without one.\n */\nexport type ProgressEvent =\n /** About to launch the browser, before the first page. */\n | { kind: \"browser\" }\n /** Discovery finished: the sitemap that supplied pages (or none), and how many URLs it gave. */\n | { kind: \"sitemap\"; source: string | null; urls: number }\n /** About to check page `index` (1-based); `queued` is every URL discovered so far. */\n | { kind: \"page\"; index: number; queued: number; url: string }\n /**\n * Page `index` finished. `violations` is axe's count for the page before the\n * severity floor is applied, so it can be higher than what the report keeps.\n * `error` is set when the page could not be loaded or analyzed. A seed that\n * fails ends the run instead, and is reported as the run's error.\n */\n | { kind: \"checked\"; index: number; url: string; violations: number; error?: string }\n /** The crawl is over: pages analyzed, and pages left in the frontier. */\n | { kind: \"done\"; checked: number; skipped: number };\n\nexport type ProgressListener = (event: ProgressEvent) => void;\n","/**\n * URL helpers for the crawl.\n *\n * Three questions, asked of every candidate before it enters the frontier:\n * what is its canonical spelling (so `/a#top` and `/a` are one page), is it\n * on a host the run is allowed to visit, and is it a page at all rather than\n * a stylesheet or a PDF. The WHATWG parser does most of the first one.\n */\nimport { A11yError } from \"../types.js\";\n\n/**\n * Canonical spelling for dedupe: parse with `new URL`, drop the fragment,\n * lowercase the hostname, drop a default port, keep path/query/trailing slash\n * exactly as given. Throws `A11yError` for an unparseable string.\n */\nexport function normalizeUrl(url: string): string {\n const parsed = parse(url);\n if (parsed === null) throw new A11yError(`Not a valid URL: \"${url}\".`);\n parsed.hash = \"\";\n return parsed.href;\n}\n\n/**\n * The key two spellings of one page share: `normalizeUrl`, then one trailing\n * `/` dropped from the path unless the path is exactly `/`. The query stays.\n * `/a` and `/a/` can be different resources, but on a static site they are one\n * page, and a crawl that checks both double-counts it. Only the seen set uses\n * this; the URL fetched and reported keeps the spelling it was given. Throws\n * `A11yError` for an unparseable string.\n */\nexport function dedupeKey(url: string): string {\n const parsed = new URL(normalizeUrl(url));\n if (parsed.pathname.length > 1 && parsed.pathname.endsWith(\"/\")) {\n parsed.pathname = parsed.pathname.slice(0, -1);\n }\n return parsed.href;\n}\n\n/** `http:` or `https:` and parseable. */\nexport function isHttpUrl(url: string): boolean {\n const parsed = parse(url);\n return parsed !== null && isHttpProtocol(parsed);\n}\n\n/**\n * Same site = same hostname (case-insensitive) and same non-default port.\n * `http://` and `https://` of one host are the same site; `www.example.com`\n * and `example.com` are not.\n */\nexport function sameHost(a: string, b: string): boolean {\n const left = parse(a);\n const right = parse(b);\n if (left === null || right === null) return false;\n // The parser has already dropped `:80` on http and `:443` on https, so an\n // empty port on both sides means \"the scheme's default\" and the two schemes\n // of one host compare equal, as the doc comment promises. Only an explicit\n // non-default port survives to differ.\n return (\n left.hostname.toLowerCase() === right.hostname.toLowerCase() &&\n left.port === right.port\n );\n}\n\n/**\n * A link worth loading as a page: http(s), not `mailto:`/`tel:`/`javascript:`/\n * `data:`, and the last path segment does not end in one of ASSET_EXTENSIONS.\n */\nexport function isPageLink(url: string): boolean {\n const parsed = parse(url);\n if (parsed === null || !isHttpProtocol(parsed)) return false;\n const last = parsed.pathname.slice(parsed.pathname.lastIndexOf(\"/\") + 1);\n const dot = last.lastIndexOf(\".\");\n if (dot === -1) return true;\n return !ASSET_EXTENSIONS.has(last.slice(dot).toLowerCase());\n}\n\nexport const ASSET_EXTENSIONS: ReadonlySet<string> = new Set([\n \".pdf\",\n \".zip\",\n \".gz\",\n \".png\",\n \".jpg\",\n \".jpeg\",\n \".gif\",\n \".svg\",\n \".webp\",\n \".avif\",\n \".ico\",\n \".css\",\n \".js\",\n \".mjs\",\n \".map\",\n \".json\",\n \".xml\",\n \".txt\",\n \".mp3\",\n \".mp4\",\n \".webm\",\n \".woff\",\n \".woff2\",\n \".ttf\",\n]);\n\nfunction parse(url: string): URL | null {\n try {\n return new URL(url);\n } catch {\n return null;\n }\n}\n\nfunction isHttpProtocol(url: URL): boolean {\n return url.protocol === \"http:\" || url.protocol === \"https:\";\n}\n","/**\n * The crawl: which pages a run visits, and in what order.\n *\n * A breadth-first walk over a FIFO frontier. Seeds go in first, then the\n * sitemap's pages, then every same-host link each visited page lists, in the\n * order it listed them. A page enters the frontier once, under its `dedupeKey`\n * (so `/a` and `/a/` are one page), keeping the spelling that arrived first.\n * Pages run one at a time so a site sees one request at a time.\n */\nimport type { AnalyzeOptions, PageAnalyzer } from \"./analyzer.js\";\nimport type { PageResult, ProgressListener } from \"../types.js\";\nimport { dedupeKey, isPageLink, normalizeUrl, sameHost } from \"./url.js\";\n\nexport interface CrawlOptions {\n /** Normalized http(s) seeds; each seed's host is in scope. */\n seeds: string[];\n /** `false` = check exactly `seeds`. */\n crawl: boolean;\n /** Hard cap on pages analyzed. Absent means no cap: the whole frontier is analyzed. */\n maxPages?: number;\n /** Extra URLs to enqueue right after the seeds (from the sitemap). */\n extra: string[];\n analyze: AnalyzeOptions;\n /** Told about each step as it happens. Absent means silent. */\n onProgress?: ProgressListener;\n}\n\nexport interface CrawlOutcome {\n /** In visit order. `source` is \"seed\", \"sitemap\" (came from `extra`) or \"link\". */\n pages: Omit<PageResult, \"score\">[];\n /** Distinct pages (by `dedupeKey`) that entered the frontier. */\n discovered: number;\n /** Left in the frontier when `maxPages` stopped the run; `0` without a cap. */\n skipped: number;\n /**\n * Dequeued and dropped unloaded, because the browser had already landed on\n * that page under another spelling. `checked + skipped + duplicates` is\n * `discovered`.\n */\n duplicates: number;\n}\n\ntype Source = PageResult[\"source\"];\n\ninterface Candidate {\n url: string;\n key: string;\n source: Source;\n}\n\n/**\n * BFS over a FIFO frontier: seeds, then `extra`, then links in the order each\n * page listed them. Every candidate goes through `normalizeUrl`, and is\n * enqueued once per `dedupeKey` (so a trailing slash does not make a second\n * page), only when `isPageLink` and `sameHost` with **any** seed. The first\n * spelling seen is the one fetched and reported. Pages run sequentially.\n * - A seed that fails to analyze rethrows (nothing was checked: exit 2).\n * - Any other page's failure is recorded as `error` and the crawl continues.\n * - A page's `finalUrl` (where the browser landed) counts as visited, so a\n * queued spelling of it is dropped at dequeue time (`duplicates`), and a\n * link to it seen afterwards is never queued.\n * - With `maxPages` set, stops when `pages.length === maxPages`; `skipped` =\n * frontier left behind. Without it, runs the frontier dry and `skipped` is 0.\n * - With `crawl: false`, `extra` is ignored and no links are followed.\n * - `onProgress` hears `browser` once before the first analyze (that is where\n * the lazy launch happens), `page` before each analyze, `checked` after\n * each, and `done` at the end. A failing seed rethrows before `checked`.\n */\nexport async function crawl(opts: CrawlOptions, analyzer: PageAnalyzer): Promise<CrawlOutcome> {\n const frontier: Candidate[] = [];\n /** Keys that entered the frontier, or that the browser landed on. */\n const seen = new Set<string>();\n /** Keys analyzed, or that the browser landed on. */\n const visited = new Set<string>();\n const progress = opts.onProgress ?? (() => undefined);\n\n const enqueue = (raw: string, source: Source): void => {\n let url: string;\n let key: string;\n try {\n url = normalizeUrl(raw);\n key = dedupeKey(url);\n } catch {\n return;\n }\n // A seed is what the user asked for, so it is never filtered as an asset;\n // it still has to be on its own host, which it is by definition.\n if (source !== \"seed\" && !isPageLink(url)) return;\n if (!opts.seeds.some((seed) => sameHost(seed, url))) return;\n if (seen.has(key)) return;\n seen.add(key);\n frontier.push({ url, key, source });\n };\n\n /** Where the browser landed is a page the run has now checked, whatever it was asked for. */\n const landed = (finalUrl: string | undefined): void => {\n if (finalUrl === undefined) return;\n try {\n const key = dedupeKey(finalUrl);\n seen.add(key);\n visited.add(key);\n } catch {\n // Not a URL the crawl could ever queue, so nothing to mark.\n }\n };\n\n for (const seed of opts.seeds) enqueue(seed, \"seed\");\n if (opts.crawl) for (const url of opts.extra) enqueue(url, \"sitemap\");\n\n const pages: CrawlOutcome[\"pages\"] = [];\n let duplicates = 0;\n const capped = (): boolean => opts.maxPages !== undefined && pages.length >= opts.maxPages;\n for (let next = 0; next < frontier.length && !capped(); next++) {\n const candidate = frontier[next];\n if (candidate === undefined) break;\n const { url, key, source } = candidate;\n if (visited.has(key)) {\n duplicates += 1;\n continue;\n }\n visited.add(key);\n const index = pages.length + 1;\n if (index === 1) progress({ kind: \"browser\" });\n progress({ kind: \"page\", index, queued: frontier.length, url });\n try {\n const analyzed = await analyzer.analyze(url, opts.analyze);\n pages.push({ ...analyzed.result, url, source });\n landed(analyzed.finalUrl);\n if (opts.crawl) for (const link of analyzed.links) enqueue(link, \"link\");\n progress({ kind: \"checked\", index, url, violations: analyzed.result.violations.length });\n } catch (err) {\n if (source === \"seed\") throw err;\n const error = err instanceof Error ? err.message : String(err);\n pages.push({ url, source, violations: [], passes: 0, incomplete: 0, error });\n progress({ kind: \"checked\", index, url, violations: 0, error });\n }\n }\n\n const skipped = frontier.length - pages.length - duplicates;\n progress({ kind: \"done\", checked: pages.length, skipped });\n return { pages, discovered: frontier.length, skipped, duplicates };\n}\n","/**\n * Sitemap discovery: the page list a site publishes for itself.\n *\n * A sitemap reaches pages no link points at, so the crawl reads it first and\n * follows links second. Nothing here is allowed to fail the run: a site with\n * no sitemap, a broken one, or one behind a firewall is a site to crawl by\n * links alone, and the outcome says so with `source: null`.\n */\nimport { DOMParser } from \"@xmldom/xmldom\";\nimport { isHttpUrl, isPageLink, normalizeUrl, sameHost } from \"./url.js\";\n\n/** `fetch` narrowed to what this module needs, so tests inject a fake. */\nexport type Fetcher = (\n url: string,\n) => Promise<{ ok: boolean; status: number; text(): Promise<string> }>;\n\nexport interface SitemapDiscovery {\n /** The sitemap (or sitemap index) URL that was read, `null` when none was usable. */\n source: string | null;\n /** Same-host page URLs from every `<loc>`, normalized and deduped, in document order. */\n urls: string[];\n}\n\nexport interface ParsedSitemap {\n kind: \"index\" | \"urlset\";\n locs: string[];\n}\n\n/** How many levels of `<sitemapindex>` nesting are followed below the first. */\nconst MAX_INDEX_DEPTH = 3;\n/** How many child sitemaps one discovery reads, across every index it meets. */\nconst MAX_CHILD_SITEMAPS = 50;\n/** A robots.txt or sitemap that has not answered in this long is \"no sitemap\". */\nconst FETCH_TIMEOUT_MS = 10_000;\n\nconst defaultFetcher: Fetcher = (url) =>\n fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS) });\n\n/**\n * The file names tried in each directory of the seed's path, in this order.\n * `sitemap.xml` is the convention; `sitemap-index.xml` is what Astro (and so\n * Starlight) emits; `sitemap_index.xml` is Yoast's and Hugo's spelling.\n */\nconst WELL_KNOWN_SITEMAP_FILES = [\"sitemap.xml\", \"sitemap-index.xml\", \"sitemap_index.xml\"];\n\n/**\n * Candidates, in order:\n * 1. GET `<origin>/robots.txt`; every `Sitemap:` line (case-insensitive key,\n * absolute URL) is a candidate, in order.\n * 2. Then, for each directory of the seed's path from the seed's own\n * directory up to `/`, nearest first (`https://h/manni/meta/fix/` walks\n * `/manni/meta/fix/`, `/manni/meta/`, `/manni/`, `/`; a seed that names a\n * file, `https://h/manni/page.html`, starts at `/manni/`), the files\n * `sitemap.xml`, `sitemap-index.xml`, `sitemap_index.xml`, in that order\n * within each directory. A project site under a path prefix (GitHub Pages)\n * cannot write to the origin's `/robots.txt` or `/sitemap.xml`, which is\n * why the walk starts at the seed and not at the root.\n * Candidates are deduped, keeping the first position of each.\n *\n * Then parse the first candidate that returns 2xx with `@xmldom/xmldom`\n * (`DOMParser`, errors swallowed); a 2xx body that is not a sitemap is skipped\n * and the next candidate tried. A `<sitemapindex>` recurses into each child\n * `<sitemap><loc>` (depth ≤ 3, ≤ 50 child sitemaps). A `<urlset>` yields its\n * `<url><loc>` values. Keep only `sameHost(seed, loc) && isPageLink(loc)`.\n * `source` is the candidate that was actually used.\n *\n * A network error, non-2xx, or unparseable body means \"no sitemap here\" —\n * never an error, and never a page failure. `.xml.gz` bodies are not\n * decompressed (deferred).\n */\nexport async function discoverSitemap(\n seed: string,\n fetcher: Fetcher = defaultFetcher,\n): Promise<SitemapDiscovery> {\n const origin = new URL(seed).origin;\n const candidates = await robotsSitemaps(`${origin}/robots.txt`, fetcher);\n for (const candidate of wellKnownCandidates(seed)) {\n if (!candidates.includes(candidate)) candidates.push(candidate);\n }\n\n for (const candidate of candidates) {\n const parsed = await fetchSitemap(candidate, fetcher);\n if (parsed === null) continue;\n const walk: Walk = { fetcher, seen: new Set([candidate]), childBudget: MAX_CHILD_SITEMAPS };\n const locs = await expand(parsed, 0, walk);\n return { source: candidate, urls: pageUrls(seed, locs) };\n }\n return { source: null, urls: [] };\n}\n\n/** Pure parser, exported for tests: returns `{ kind: \"index\" | \"urlset\", locs: string[] }` or `null`. */\nexport function parseSitemapXml(text: string): ParsedSitemap | null {\n if (text.trim() === \"\") return null;\n let root: XmlNode | null;\n try {\n // Every parse problem is routed to `onError` and ignored; what matters is\n // whether a sitemap root came out the other side.\n const doc = new DOMParser({ onError: () => undefined }).parseFromString(text, \"text/xml\");\n root = doc.documentElement;\n } catch {\n return null;\n }\n if (root === null) return null;\n const kind = root.localName;\n if (kind !== \"sitemapindex\" && kind !== \"urlset\") return null;\n const entry = kind === \"sitemapindex\" ? \"sitemap\" : \"url\";\n const locs: string[] = [];\n for (const child of childElements(root, entry)) {\n for (const loc of childElements(child, \"loc\")) {\n const value = (loc.textContent ?? \"\").trim();\n if (value !== \"\") locs.push(value);\n }\n }\n return { kind: kind === \"sitemapindex\" ? \"index\" : \"urlset\", locs };\n}\n\ntype XmlDocument = ReturnType<DOMParser[\"parseFromString\"]>;\n/**\n * xmldom's `Node`, reached through the parser's own types rather than an\n * import so the alias tracks whatever the installed version declares. It is\n * enough here: `localName`, `textContent` and the sibling walk are all on\n * `Node`, and `documentElement` narrows to it.\n */\ntype XmlNode = NonNullable<XmlDocument[\"firstChild\"]>;\n\n/** Element children of `node` whose local name is `name`, in document order. */\nfunction childElements(node: XmlNode, name: string): XmlNode[] {\n const out: XmlNode[] = [];\n for (let n = node.firstChild; n !== null; n = n.nextSibling) {\n if (n.nodeType === 1 && n.localName === name) out.push(n);\n }\n return out;\n}\n\ninterface Walk {\n fetcher: Fetcher;\n /** Sitemap URLs already read, so an index that lists itself terminates. */\n seen: Set<string>;\n /** Child sitemaps still allowed; shared across the whole recursion. */\n childBudget: number;\n}\n\nasync function expand(parsed: ParsedSitemap, depth: number, walk: Walk): Promise<string[]> {\n if (parsed.kind === \"urlset\") return parsed.locs;\n if (depth >= MAX_INDEX_DEPTH) return [];\n const out: string[] = [];\n for (const child of parsed.locs) {\n if (walk.childBudget <= 0) break;\n if (!isHttpUrl(child) || walk.seen.has(child)) continue;\n walk.seen.add(child);\n walk.childBudget -= 1;\n const nested = await fetchSitemap(child, walk.fetcher);\n if (nested === null) continue;\n out.push(...(await expand(nested, depth + 1, walk)));\n }\n return out;\n}\n\n/**\n * The well-known sitemap file names in every directory of the seed's path,\n * nearest directory first, root last. Query and fragment are dropped; the\n * directory of `/manni/page.html` is `/manni/`, of `/manni/` is itself.\n */\nfunction wellKnownCandidates(seed: string): string[] {\n const url = new URL(seed);\n const directories = ancestorDirectories(url.pathname);\n return directories.flatMap((dir) =>\n WELL_KNOWN_SITEMAP_FILES.map((file) => `${url.origin}${dir}${file}`),\n );\n}\n\n/**\n * `/manni/meta/fix/` → `[\"/manni/meta/fix/\", \"/manni/meta/\", \"/manni/\", \"/\"]`;\n * `/manni/page.html` → `[\"/manni/\", \"/\"]`; `/` → `[\"/\"]`.\n */\nfunction ancestorDirectories(pathname: string): string[] {\n let dir = pathname.slice(0, pathname.lastIndexOf(\"/\") + 1);\n const out: string[] = [];\n for (;;) {\n out.push(dir);\n if (dir === \"/\") return out;\n // Drop the trailing slash, then everything after the previous one.\n const parent = dir.slice(0, dir.lastIndexOf(\"/\", dir.length - 2) + 1);\n dir = parent === \"\" ? \"/\" : parent;\n }\n}\n\n/** The `Sitemap:` candidates from a robots.txt, or none when it is missing. */\nasync function robotsSitemaps(url: string, fetcher: Fetcher): Promise<string[]> {\n const text = await fetchText(url, fetcher);\n if (text === null) return [];\n const out: string[] = [];\n for (const line of text.split(/\\r?\\n/)) {\n const match = /^\\s*sitemap\\s*:\\s*(\\S+)/i.exec(line);\n const candidate = match?.[1];\n if (candidate !== undefined && isHttpUrl(candidate) && !out.includes(candidate)) {\n out.push(candidate);\n }\n }\n return out;\n}\n\nasync function fetchSitemap(url: string, fetcher: Fetcher): Promise<ParsedSitemap | null> {\n const text = await fetchText(url, fetcher);\n return text === null ? null : parseSitemapXml(text);\n}\n\n/** The body of a 2xx response, or `null` for anything else, thrown included. */\nasync function fetchText(url: string, fetcher: Fetcher): Promise<string | null> {\n try {\n const response = await fetcher(url);\n if (!response.ok) return null;\n return await response.text();\n } catch {\n return null;\n }\n}\n\n/** Filter, normalize and dedupe the `<loc>` values into crawlable page URLs. */\nfunction pageUrls(seed: string, locs: string[]): string[] {\n const out: string[] = [];\n const seen = new Set<string>();\n for (const loc of locs) {\n if (!isHttpUrl(loc) || !sameHost(seed, loc) || !isPageLink(loc)) continue;\n const url = normalizeUrl(loc);\n if (seen.has(url)) continue;\n seen.add(url);\n out.push(url);\n }\n return out;\n}\n","/**\n * `manni a11y check`, the command core.\n *\n * Validates the seeds, finds the sitemap, runs the crawl, drops the findings\n * below the severity floor, scores each page and totals the summary. No CLI\n * and no IO of its own beyond the injected analyzer and fetcher, so it can be\n * tested end to end with neither a browser nor a network.\n */\nimport type { PageAnalyzer } from \"../core/analyzer.js\";\nimport { crawl, type CrawlOutcome } from \"../core/crawl.js\";\nimport { discoverSitemap, type Fetcher, type SitemapDiscovery } from \"../core/sitemap.js\";\nimport { isHttpUrl, normalizeUrl } from \"../core/url.js\";\nimport {\n A11yError,\n meetsSeverity,\n type CheckRun,\n type CheckSummary,\n type Severity,\n type PageResult,\n type ProgressListener,\n} from \"../types.js\";\n\nexport interface CheckOptions {\n /** Seeds as typed (validated and normalized here). */\n urls: string[];\n /** Follow the sitemap and same-host links. Default `true`. */\n crawl: boolean;\n /** Stop after this many pages. Absent means no cap: every discovered page is checked. */\n maxPages?: number;\n /** axe tags to restrict to; empty is axe's default rule set. Default `[]`. */\n tags: string[];\n /** Minimum family severity reported and counted. Default `\"notice\"`, everything. */\n severity: Severity;\n /** Per-page navigation timeout in ms. Default `30000`. */\n timeout: number;\n}\n\nexport interface CheckDeps {\n analyzer: PageAnalyzer;\n /** Defaults to global `fetch`. */\n fetcher?: Fetcher;\n /**\n * Told about each step as it happens: `sitemap` once discovery is done\n * (only when crawling), then everything the crawl reports. Absent means\n * silent.\n */\n onProgress?: ProgressListener;\n}\n\n/**\n * `maxPages` is deliberately absent: the default is no cap. A capped crawl\n * reports a partial site as checked, so the cap is opt-in, through\n * `--max-pages` or the config key.\n */\nexport const CHECK_DEFAULTS: Readonly<Omit<CheckOptions, \"urls\">> = Object.freeze({\n crawl: true,\n tags: [],\n severity: \"notice\",\n timeout: 30000,\n});\n\n/**\n * 1. `urls.length === 0` → A11yError(\"No URLs to check. Pass one or more, or set `a11y.urls` in manni.config.yaml.\")\n * 2. Any non-http(s) url → A11yError(`Not an http(s) URL: \"<url>\".`)\n * 3. When `crawl`: `discoverSitemap(firstSeed)` (one sitemap per run, the first seed's origin).\n * 4. `crawl(...)`, then per page: drop violations below `severity`, compute `score`.\n * 5. Build `CheckSummary`. Always awaits `analyzer.close()` in `finally`.\n */\nexport async function runCheck(opts: CheckOptions, deps: CheckDeps): Promise<CheckRun> {\n const { analyzer } = deps;\n try {\n if (opts.urls.length === 0) {\n throw new A11yError(\n \"No URLs to check. Pass one or more, or set `a11y.urls` in manni.config.yaml.\",\n );\n }\n for (const url of opts.urls) {\n if (!isHttpUrl(url)) throw new A11yError(`Not an http(s) URL: \"${url}\".`);\n }\n const seeds = opts.urls.map(normalizeUrl);\n\n let sitemap: SitemapDiscovery = { source: null, urls: [] };\n const first = seeds[0];\n if (opts.crawl && first !== undefined) {\n sitemap = await discoverSitemap(first, deps.fetcher);\n deps.onProgress?.({ kind: \"sitemap\", source: sitemap.source, urls: sitemap.urls.length });\n }\n\n const outcome = await crawl(\n {\n seeds,\n crawl: opts.crawl,\n maxPages: opts.maxPages,\n extra: sitemap.urls,\n analyze: { tags: opts.tags, timeout: opts.timeout },\n onProgress: deps.onProgress,\n },\n analyzer,\n );\n\n const results = outcome.pages.map((page) => finishPage(page, opts.severity));\n return {\n results,\n summary: summarize(results, outcome, sitemap.source, opts.crawl),\n };\n } finally {\n await analyzer.close();\n }\n}\n\n/** Apply the severity floor, then score what is left. */\nfunction finishPage(page: Omit<PageResult, \"score\">, floor: Severity): PageResult {\n if (page.error !== undefined) return { ...page, violations: [], score: null };\n const violations = page.violations.filter((v) => meetsSeverity(v.severity, floor));\n const applicable = page.passes + violations.length;\n const score = applicable === 0 ? null : Math.round((100 * page.passes) / applicable);\n return { ...page, violations, score };\n}\n\nfunction summarize(\n results: PageResult[],\n { discovered, skipped, duplicates }: CrawlOutcome,\n sitemap: string | null,\n crawl: boolean,\n): CheckSummary {\n // Spelled out so the compiler, not a test, says when the family scale moves.\n const bySeverity: Record<Severity, number> = { notice: 0, warning: 0, error: 0 };\n let failed = 0;\n let violations = 0;\n for (const page of results) {\n if (page.error !== undefined || page.violations.length > 0) failed += 1;\n for (const violation of page.violations) {\n violations += 1;\n bySeverity[violation.severity] += 1;\n }\n }\n return {\n discovered,\n checked: results.length,\n skipped,\n duplicates,\n failed,\n violations,\n bySeverity,\n sitemap,\n crawl,\n };\n}\n","/**\n * The browser seam.\n *\n * Everything that needs a real page — navigation, the live DOM's links, axe\n * itself — sits behind `PageAnalyzer`, so the crawl and the check core can be\n * exercised with a canned analyzer and no browser. The Playwright-backed\n * implementation lives here too, behind the same interface.\n */\nimport { AxeBuilder } from \"@axe-core/playwright\";\nimport { chromium, type Browser, type Page } from \"playwright-core\";\nimport {\n A11yError,\n isAxeImpact,\n type AxeImpact,\n type PageResult,\n type Severity,\n type Violation,\n type ViolationNode,\n} from \"../types.js\";\n\nexport interface AnalyzeOptions {\n /** axe tags to restrict to; empty = axe defaults. */\n tags: string[];\n /** Navigation timeout in ms. */\n timeout: number;\n}\n\nexport interface AnalyzedPage {\n /** Raw result: every violation regardless of severity; `source` and `score` are filled in by `runCheck`. */\n result: Omit<PageResult, \"source\" | \"score\">;\n /** Absolute `href` of every `a[href]` in the live DOM after load, unfiltered. */\n links: string[];\n /**\n * The browser's URL once navigation and any redirects settled. The crawl\n * marks it visited so a later queued spelling of the same page is not\n * loaded again. Absent when the analyzer does not know it.\n */\n finalUrl?: string;\n}\n\nexport interface PageAnalyzer {\n /**\n * Load `url` and run axe. Rejects with `A11yError` on navigation failure or\n * timeout (message names the URL and the underlying reason); the caller\n * decides whether that is fatal (seed) or a per-page `error` (crawled page).\n */\n analyze(url: string, opts: AnalyzeOptions): Promise<AnalyzedPage>;\n /** Close the browser. Safe to call when nothing was launched, and twice. */\n close(): Promise<void>;\n}\n\nexport type BrowserChannel = \"chrome\" | \"msedge\" | \"chromium\";\n\n/** The message when nothing launches; the same words the CLI's ladder promises. */\nexport const NO_BROWSER_MESSAGE =\n \"No browser found. Install one with `npx playwright install chromium`, or install Google Chrome or Microsoft Edge.\";\n\n/** The launch order: what the machine already has first, Playwright's own download last. */\nconst CHANNELS: readonly BrowserChannel[] = [\"chrome\", \"msedge\", \"chromium\"];\n\nfunction launch(channel: BrowserChannel): Promise<Browser> {\n return channel === \"chromium\"\n ? chromium.launch({ headless: true })\n : chromium.launch({ channel, headless: true });\n}\n\n/** The first channel that launches, still open, or `null` when none does. */\nasync function launchAny(): Promise<{ browser: Browser; channel: BrowserChannel } | null> {\n for (const channel of CHANNELS) {\n try {\n return { browser: await launch(channel), channel };\n } catch {\n // Not installed, or not launchable here. Try the next one.\n }\n }\n return null;\n}\n\n/**\n * Try, in order: `chromium.launch({ channel: \"chrome\", headless: true })`,\n * `{ channel: \"msedge\" }`, `chromium.launch()` (Playwright's own download).\n * Returns the first that launches, closed again, or `null`. Exported so the\n * integration suite can `describe.skipIf`.\n */\nexport async function findBrowser(): Promise<BrowserChannel | null> {\n const found = await launchAny();\n if (found === null) return null;\n await found.browser.close();\n return found.channel;\n}\n\n/** axe's result shapes, as `@axe-core/playwright` declares them; no direct axe-core import. */\ntype AxeResults = Awaited<ReturnType<AxeBuilder[\"analyze\"]>>;\ntype AxeResult = AxeResults[\"violations\"][number];\ntype AxeNode = AxeResult[\"nodes\"][number];\n\ninterface Session {\n browser: Browser;\n page: Page;\n}\n\n/**\n * Playwright-backed analyzer. Lazy: the browser launches on the first\n * `analyze`, one context and one page are reused for every URL.\n * - `page.goto(url, { waitUntil: \"load\", timeout })`; `finalUrl` is `page.url()` after it\n * - links: every `a[href]`'s absolute `href` from the live DOM\n * - `new AxeBuilder({ page })`, `.withTags(tags)` only when `tags.length > 0`, `.analyze()`\n * - map axe `Result` → `Violation` (`severity` from `severityOf(impact)`, `impact` kept as\n * axe's word with `null`/`undefined` → \"minor\"; node `target` joined with \" \";\n * `failureSummary ?? \"\"`), `passes.length`, `incomplete.length`\n * - launch failure on every channel → `A11yError(NO_BROWSER_MESSAGE)`\n */\nexport function createPlaywrightAnalyzer(): PageAnalyzer {\n let session: Promise<Session> | null = null;\n\n const open = (): Promise<Session> => {\n session ??= (async () => {\n const found = await launchAny();\n if (found === null) throw new A11yError(NO_BROWSER_MESSAGE);\n const context = await found.browser.newContext();\n const page = await context.newPage();\n return { browser: found.browser, page };\n })();\n return session;\n };\n\n return {\n async analyze(url, opts) {\n const { page } = await open();\n try {\n await page.goto(url, { waitUntil: \"load\", timeout: opts.timeout });\n } catch (err) {\n throw new A11yError(`Could not load ${url}: ${reason(err)}`);\n }\n const links = await page.$$eval(\"a[href]\", (anchors): string[] =>\n anchors.map((a) => (a as unknown as { href: string }).href),\n );\n let builder = new AxeBuilder({ page });\n if (opts.tags.length > 0) builder = builder.withTags(opts.tags);\n let results: AxeResults;\n try {\n results = await builder.analyze();\n } catch (err) {\n throw new A11yError(`Could not analyze ${url}: ${reason(err)}`);\n }\n return {\n result: {\n url,\n violations: results.violations.map(toViolation),\n passes: results.passes.length,\n incomplete: results.incomplete.length,\n },\n links,\n finalUrl: page.url(),\n };\n },\n\n async close() {\n if (session === null) return;\n const pending = session;\n session = null;\n try {\n const { browser } = await pending;\n await browser.close();\n } catch {\n // The launch itself failed: there is nothing to close.\n }\n },\n };\n}\n\n/** What axe may put in `impact`; the same union `@axe-core/playwright` declares. */\ntype ImpactValue = AxeResult[\"impact\"];\n\n/**\n * axe's impact onto the family severity scale (`src/shared/severity.ts`).\n * Four levels fold onto three: `critical` and `serious` are both `error`,\n * `moderate` is `warning`, `minor` is `notice`. A missing impact, which axe\n * reports as `null` for a rule with no impact set, is the lowest level. The\n * original word is kept on the violation as `impact`, so nothing is lost for\n * anyone looking the rule up where axe names it.\n */\nexport function severityOf(impact: ImpactValue | null | undefined): Severity {\n switch (impact) {\n case \"critical\":\n case \"serious\":\n return \"error\";\n case \"moderate\":\n return \"warning\";\n default:\n return \"notice\";\n }\n}\n\n/** axe's word as it stands, or `minor` when it gave none. */\nfunction impactOf(impact: ImpactValue | null | undefined): AxeImpact {\n return impact != null && isAxeImpact(impact) ? impact : \"minor\";\n}\n\nfunction toViolation(result: AxeResult): Violation {\n return {\n id: result.id,\n severity: severityOf(result.impact),\n impact: impactOf(result.impact),\n help: result.help,\n helpUrl: result.helpUrl,\n tags: result.tags,\n nodes: result.nodes.map(toNode),\n };\n}\n\nfunction toNode(node: AxeNode): ViolationNode {\n return {\n // A shadow-DOM target is a nested list of selectors; flatten it the same way.\n target: node.target.map((t) => (Array.isArray(t) ? t.join(\" \") : t)).join(\" \"),\n html: node.html,\n summary: node.failureSummary ?? \"\",\n };\n}\n\n/**\n * The first line of a Playwright error. The rest is a call log that repeats\n * the URL and the timeout, which the caller's message already carries.\n */\nfunction reason(err: unknown): string {\n const message = err instanceof Error ? err.message : String(err);\n return message.split(\"\\n\")[0]?.trim() ?? message;\n}\n","/**\n * The `a11y:` key of the family config file (`manni.config.yaml`).\n *\n * Finding the file is the shared layer's job (src/shared/config-file.ts);\n * what the section may contain is decided here. The posture is meta's: an\n * unknown key or a wrong type is an error that names the file and the key,\n * because a misspelled `maxPages:` that was silently ignored would run the\n * crawl on defaults and read as a clean pass.\n */\nimport {\n findConfigFile,\n readConfigFile,\n type ConfigFileOptions,\n} from \"../../shared/config-file.js\";\nimport { A11yError, SEVERITIES, isSeverity, type Severity } from \"../types.js\";\nimport { isHttpUrl } from \"./url.js\";\n\nexport interface A11yConfig {\n urls?: string[];\n crawl?: boolean;\n /** Cap on pages checked. Absent means no cap. */\n maxPages?: number;\n tags?: string[];\n severity?: Severity;\n timeout?: number;\n}\n\nexport interface LoadedA11yConfig {\n config: A11yConfig;\n /** Where it came from, for messages. `null` when no file was found or `--no-config`. */\n source: string | null;\n}\n\n/** The tool's key in the family file. */\nconst SECTION = \"a11y\";\n\n/**\n * The keys the section may carry. Adding a key to `A11yConfig` means adding\n * it here too, or a config using it is rejected; that coupling is the point.\n */\nconst CONFIG_KEYS = [\"urls\", \"crawl\", \"maxPages\", \"tags\", \"severity\", \"timeout\"] as const;\n\nconst CONFIG_FILE: ConfigFileOptions = {\n section: SECTION,\n // The a11y tool never had a pre-family file of its own.\n legacyNames: [],\n toError: (message) => new A11yError(message),\n};\n\n/**\n * Discover (or read `explicitPath`) through the shared family-file loader with\n * `{ section: \"a11y\", legacyNames: [], toError: (m) => new A11yError(m) }`.\n * Unknown keys, wrong types, empty `urls` entries and non-`http(s)` urls are\n * `A11yError`s naming the file and key. `null` config (empty section) is `{}`.\n */\nexport async function loadA11yConfig(\n cwd: string,\n explicitPath?: string,\n): Promise<LoadedA11yConfig> {\n const file =\n explicitPath === undefined\n ? await findConfigFile(cwd, CONFIG_FILE)\n : await readConfigFile(explicitPath, cwd, CONFIG_FILE);\n if (file === null) return { config: {}, source: null };\n return { config: parseA11yConfig(file.value, file.source), source: file.source };\n}\n\n/** Pure parser, exported for tests. */\nexport function parseA11yConfig(value: unknown, source: string): A11yConfig {\n if (value == null) return {};\n if (typeof value !== \"object\" || Array.isArray(value)) {\n throw new A11yError(`${source}: \\`${SECTION}:\\` must be a mapping.`);\n }\n const obj = value as Record<string, unknown>;\n for (const key of Object.keys(obj)) {\n if (!(CONFIG_KEYS as readonly string[]).includes(key)) {\n throw new A11yError(\n `${source}: \\`${SECTION}:\\` has unknown key \"${key}\". Supported keys: ${CONFIG_KEYS.join(\", \")}.`,\n );\n }\n }\n\n const config: A11yConfig = {};\n if (obj.urls !== undefined) config.urls = asUrls(obj.urls, source);\n if (obj.crawl !== undefined) config.crawl = asBoolean(obj.crawl, \"crawl\", source);\n if (obj.maxPages !== undefined) {\n config.maxPages = asPositiveInteger(obj.maxPages, \"maxPages\", source);\n }\n if (obj.tags !== undefined) config.tags = asStringList(obj.tags, \"tags\", source);\n if (obj.severity !== undefined) config.severity = asSeverity(obj.severity, source);\n if (obj.timeout !== undefined) {\n config.timeout = asPositiveInteger(obj.timeout, \"timeout\", source);\n }\n return config;\n}\n\nfunction asStringList(value: unknown, field: string, source: string): string[] {\n if (!Array.isArray(value) || !value.every((v) => typeof v === \"string\")) {\n throw new A11yError(`${source}: \"${SECTION}.${field}\" must be a list of strings.`);\n }\n return value;\n}\n\nfunction asUrls(value: unknown, source: string): string[] {\n const urls = asStringList(value, \"urls\", source);\n urls.forEach((url, i) => {\n if (!isHttpUrl(url)) {\n throw new A11yError(\n `${source}: \"${SECTION}.urls[${i}]\" must be an http(s) URL, got \"${url}\".`,\n );\n }\n });\n return urls;\n}\n\nfunction asBoolean(value: unknown, field: string, source: string): boolean {\n if (typeof value !== \"boolean\") {\n throw new A11yError(`${source}: \"${SECTION}.${field}\" must be a boolean.`);\n }\n return value;\n}\n\nfunction asPositiveInteger(value: unknown, field: string, source: string): number {\n if (typeof value !== \"number\" || !Number.isInteger(value) || value < 1) {\n throw new A11yError(`${source}: \"${SECTION}.${field}\" must be an integer >= 1.`);\n }\n return value;\n}\n\nfunction asSeverity(value: unknown, source: string): Severity {\n if (typeof value !== \"string\" || !isSeverity(value)) {\n throw new A11yError(\n `${source}: \"${SECTION}.severity\" must be one of ${SEVERITIES.join(\", \")}.`,\n );\n }\n return value;\n}\n","/**\n * `--format github`: one workflow-command annotation per finding.\n *\n * There is no file to anchor to, since the check ran against a URL, so the\n * annotation carries the rule id as its title and names the page in the\n * message. Empty when the run is clean, so a clean CI step logs nothing.\n */\nimport {\n escapeWorkflowCommandMessage,\n escapeWorkflowCommandProperty,\n} from \"../../shared/github.js\";\nimport type { CheckRun, Severity } from \"../types.js\";\n\n/** The three levels a workflow command can carry. */\nexport type AnnotationLevel = \"error\" | \"warning\" | \"notice\";\n\n/**\n * The annotation level for a finding of the given severity.\n *\n * The family scale (`src/shared/severity.ts`) was chosen to match GitHub's,\n * so the map is one-to-one and this is the identity. It stays a function,\n * and stays exported, because it is the seam: the translation from a\n * domain's severity to an output's levels happens here and nowhere else,\n * and a reporter for a sink with another scale (SARIF's `note`) would carry\n * its own. axe's four impacts were folded onto these three by the analyzer\n * (`severityOf`), before any reporter saw the finding. Proposal 0035,\n * stress test 10.\n */\nexport function annotationLevel(severity: Severity): AnnotationLevel {\n return severity;\n}\n\nexport function renderGithub(run: CheckRun): string {\n const lines: string[] = [];\n for (const page of run.results) {\n if (page.error !== undefined) {\n // A page that did not load has no severity to translate. It is the most\n // serious thing a run can hold, so it is always an error.\n lines.push(\n `::error title=a11y/load::${escapeWorkflowCommandMessage(`${page.url}: ${page.error}`)}`,\n );\n continue;\n }\n for (const v of page.violations) {\n const n = v.nodes.length;\n const title = escapeWorkflowCommandProperty(`a11y/${v.id}`);\n const msg = escapeWorkflowCommandMessage(\n `${v.help} — ${n} node${n === 1 ? \"\" : \"s\"} on ${page.url} (${v.helpUrl})`,\n );\n lines.push(`::${annotationLevel(v.severity)} title=${title}::${msg}`);\n }\n }\n return lines.join(\"\\n\");\n}\n","/**\n * `--format json`: the `CheckRun` as it is, pretty-printed. Key order is the\n * order the types declare, so the envelope is stable from run to run.\n */\nimport type { CheckRun } from \"../types.js\";\n\nexport function renderJson(run: CheckRun): string {\n return JSON.stringify(run, null, 2);\n}\n","/**\n * `--format pretty`: the report a person reads in a terminal.\n *\n * One line per page, and under a failing page one line per rule followed by\n * the first three elements that failed it, each with axe's own statement of\n * which condition was not met. That per-element line is the deterministic\n * remediation: which rule, which selector, what to change.\n *\n * Colors carry the meanings meta already gave them: ✓ green, ✗ red, URLs\n * cyan, and severity from dim (notice) through yellow (warning) to red\n * (error).\n *\n * Each violation line leads with the family severity, which is what the\n * floor and the exit code are decided on. axe's own word follows the rule id\n * in parentheses, `(axe: critical)`, so the line can still be matched\n * against the Deque rule page and the axe DevTools report that use it.\n */\nimport { palette, type Colors } from \"../../shared/color.js\";\nimport {\n SEVERITIES,\n type CheckRun,\n type Severity,\n type PageResult,\n type Violation,\n} from \"../types.js\";\nimport type { RenderOptions } from \"./index.js\";\n\n/** How many failing elements are listed under one rule before `(+N more)`. */\nconst MAX_NODES = 3;\n\nexport function renderPretty(run: CheckRun, opts: RenderOptions): string {\n const c = palette(opts.color);\n const { summary } = run;\n const lines: string[] = [];\n\n lines.push(`Checked ${summary.checked} of ${summary.discovered} pages (${where(run, c)})`);\n\n for (const page of run.results) {\n if (page.error !== undefined) {\n lines.push(`${c.red(\"✗\")} ${c.cyan(page.url)} could not load: ${page.error}`);\n continue;\n }\n if (page.violations.length === 0) {\n if (!opts.quiet) lines.push(`${c.green(\"✓\")} ${c.cyan(page.url)} score ${scoreText(page)}`);\n continue;\n }\n lines.push(\n `${c.red(\"✗\")} ${c.cyan(page.url)} score ${scoreText(page)} ${severityCounts(page.violations, c)}`,\n );\n for (const v of page.violations) lines.push(...violationLines(v, c));\n }\n\n const failed = summary.failed;\n const footer =\n `${summary.violations} violation${summary.violations === 1 ? \"\" : \"s\"} on ${failed} of ${summary.checked} pages` +\n (summary.skipped > 0 ? `; ${summary.skipped} skipped (--max-pages)` : \"\") +\n (summary.duplicates > 0\n ? `; ${summary.duplicates} duplicate${summary.duplicates === 1 ? \"\" : \"s\"} dropped`\n : \"\");\n lines.push(\"\");\n lines.push(failed > 0 ? c.red(footer) : c.green(footer));\n return lines.join(\"\\n\");\n}\n\n/**\n * How the pages were found. `--no-crawl` never looks for a sitemap, so a null\n * `sitemap` alone cannot tell \"no crawl\" from \"crawled, found no sitemap\".\n */\nfunction where(run: CheckRun, c: Colors): string {\n const { summary } = run;\n if (!summary.crawl) return \"no crawl\";\n if (summary.sitemap === null) return \"no sitemap; followed links\";\n return `sitemap: ${c.cyan(summary.sitemap)}`;\n}\n\nfunction scoreText(page: PageResult): string {\n return page.score === null ? \"n/a\" : String(page.score);\n}\n\n/** `2 errors, 1 notice`: most severe first, pluralised, zeros omitted. */\nfunction severityCounts(violations: Violation[], c: Colors): string {\n const counts: Record<Severity, number> = { notice: 0, warning: 0, error: 0 };\n for (const v of violations) counts[v.severity] += 1;\n return [...SEVERITIES]\n .reverse()\n .filter((severity) => counts[severity] > 0)\n .map((severity) => {\n const n = counts[severity];\n return paintSeverity(`${n} ${severity}${n === 1 ? \"\" : \"s\"}`, severity, c);\n })\n .join(\", \");\n}\n\nfunction violationLines(v: Violation, c: Colors): string[] {\n const n = v.nodes.length;\n const lines = [\n ` ${paintSeverity(v.severity, v.severity, c)} ${v.id} ${c.dim(`(axe: ${v.impact})`)} ${n} node${n === 1 ? \"\" : \"s\"} ${v.help} ${c.dim(v.helpUrl)}`,\n ];\n for (const node of v.nodes.slice(0, MAX_NODES)) {\n lines.push(` ${node.target} → ${oneLine(node.summary)}`);\n }\n if (n > MAX_NODES) lines.push(c.dim(` (+${n - MAX_NODES} more)`));\n return lines;\n}\n\n/**\n * axe's failureSummary is a heading line followed by one indented line per\n * unmet condition. On one line: the heading, then the conditions joined by\n * `; `.\n */\nfunction oneLine(summary: string): string {\n const [head, ...rest] = summary\n .split(\"\\n\")\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n if (head === undefined) return \"\";\n return rest.length === 0 ? head : `${head} ${rest.join(\"; \")}`;\n}\n\nfunction paintSeverity(text: string, severity: Severity, c: Colors): string {\n switch (severity) {\n case \"notice\":\n return c.dim(text);\n case \"warning\":\n return c.yellow(text);\n case \"error\":\n return c.red(text);\n }\n}\n","/**\n * The a11y reporters render a `CheckRun` to a string. The command layer writes\n * the result to stdout; diagnostics go to stderr separately.\n */\nimport { A11yError, type CheckRun } from \"../types.js\";\nimport { renderGithub } from \"./github.js\";\nimport { renderJson } from \"./json.js\";\nimport { renderPretty } from \"./pretty.js\";\n\nexport { renderGithub, annotationLevel } from \"./github.js\";\nexport type { AnnotationLevel } from \"./github.js\";\nexport { renderJson } from \"./json.js\";\nexport { renderPretty } from \"./pretty.js\";\n\n/**\n * Every value `--format` accepts, in the order help and error messages list\n * them. Stated once, so the union, the guard, the option text and the error\n * cannot drift apart. SARIF and JUnit are deferred (proposal 0035).\n */\nexport const A11Y_FORMATS = [\"pretty\", \"json\", \"github\"] as const;\nexport type A11yFormat = (typeof A11Y_FORMATS)[number];\n\n/** `\"pretty | json | github\"`, for messages and help text. */\nexport const A11Y_FORMAT_LIST: string = A11Y_FORMATS.join(\" | \");\n\nexport function isA11yFormat(value: string): value is A11yFormat {\n return (A11Y_FORMATS as readonly string[]).includes(value);\n}\n\nexport interface RenderOptions {\n /** From shared `shouldColor`. */\n color: boolean;\n /** pretty only: hide pages with no remaining violations. */\n quiet: boolean;\n}\n\n/** Returns the full text without a trailing newline; `github` returns \"\" when clean. */\nexport function render(format: A11yFormat, run: CheckRun, opts: RenderOptions): string {\n switch (format) {\n case \"pretty\":\n return renderPretty(run, opts);\n case \"json\":\n return renderJson(run);\n case \"github\":\n return renderGithub(run);\n default: {\n // Exhaustive: a format added to `A11Y_FORMATS` without a case here is a\n // compile error; the throw is for a caller who bypassed the guard.\n const unreachable: never = format;\n throw new A11yError(\n `Unknown report format ${JSON.stringify(unreachable)}. Use ${A11Y_FORMAT_LIST}.`,\n );\n }\n }\n}\n","/**\n * Progress on stderr, while the crawl runs.\n *\n * The browser launch alone takes seconds and a fifty-page site takes a\n * minute, and a command that says nothing for that long reads as hung. So\n * the run narrates itself on stderr, where a diagnostic belongs; stdout stays\n * the report, and `-f json | jq` keeps working.\n *\n * Two renderings. On a terminal, one status line rewritten in place\n * (`\\r`, erase line, then the text, no newline) and cleared on `done`, so the\n * report on stdout is not preceded by a dangling line. Off a terminal, one\n * plain line per event, newline-terminated and prefixed the way `warn()`\n * writes, with no escape codes, since a CI log keeps every line.\n *\n * Colours keep the meanings meta gave them: ✓ green, ✗ red, URLs cyan, the\n * counter dim. They apply on a terminal only.\n */\nimport { palette, type Colors } from \"../../shared/color.js\";\nimport { programName } from \"../../shared/program-name.js\";\nimport type { ProgressEvent, ProgressListener } from \"../types.js\";\n\nexport interface ProgressOptions {\n /** Where to write: `process.stderr`, or a fake in tests. */\n stream: { write(s: string): boolean; isTTY?: boolean; columns?: number };\n /** Paint the status line. Ignored off a terminal. */\n color: boolean;\n /** Rewrite one line in place (true) or append a line per event (false). */\n tty: boolean;\n}\n\n/** Carriage return, then erase the whole line: the start of every status line. */\nexport const CLEAR_LINE = \"\\r\\x1b[2K\";\n\n/** The width a status line is fitted to when the stream does not say. */\nconst DEFAULT_COLUMNS = 80;\n\n/** Returns a listener that renders events to `stream`. */\nexport function createProgressReporter(opts: ProgressOptions): ProgressListener {\n return opts.tty ? terminalReporter(opts) : plainReporter(opts.stream);\n}\n\nfunction plural(n: number, noun: string): string {\n return `${n} ${noun}${n === 1 ? \"\" : \"s\"}`;\n}\n\n/** `[3/51]`, from the last `page` event; `checked` carries no `queued` of its own. */\nfunction counter(index: number, queued: number): string {\n return `[${index}/${queued}]`;\n}\n\nfunction terminalReporter(opts: ProgressOptions): ProgressListener {\n const { stream } = opts;\n const c = palette(opts.color);\n let queued = 0;\n\n const show = (text: string): void => {\n stream.write(`${CLEAR_LINE}${text}`);\n };\n /** `prefix`, the URL, then `suffix`; the URL shortened in the middle to fit the line. */\n const showUrl = (prefix: string, url: string, suffix = \"\"): void => {\n const columns = stream.columns ?? DEFAULT_COLUMNS;\n const fitted = truncateMiddle(url, columns - visibleLength(prefix) - suffix.length);\n show(`${prefix}${c.cyan(fitted)}${suffix}`);\n };\n\n return (event: ProgressEvent): void => {\n switch (event.kind) {\n case \"browser\":\n show(\"Starting browser…\");\n return;\n case \"sitemap\":\n if (event.source === null) show(\"No sitemap; following links\");\n else showUrl(\"Sitemap: \", event.source, ` (${plural(event.urls, \"page\")})`);\n return;\n case \"page\":\n queued = event.queued;\n showUrl(`${c.dim(counter(event.index, queued))} `, event.url);\n return;\n case \"checked\":\n showUrl(`${c.dim(counter(event.index, queued))} ${outcome(event, c)}`, event.url);\n return;\n case \"done\":\n stream.write(CLEAR_LINE);\n return;\n }\n };\n}\n\n/** `✓ `, `✗ 2 violations `, or `✗ could not load: … `: what goes between the counter and the URL. */\nfunction outcome(event: Extract<ProgressEvent, { kind: \"checked\" }>, c: Colors): string {\n if (event.error !== undefined) return `${c.red(\"✗\")} could not load: ${event.error} `;\n if (event.violations === 0) return `${c.green(\"✓\")} `;\n return `${c.red(\"✗\")} ${plural(event.violations, \"violation\")} `;\n}\n\nfunction plainReporter(stream: ProgressOptions[\"stream\"]): ProgressListener {\n let queued = 0;\n const say = (text: string): void => {\n stream.write(`${programName()}: ${text}\\n`);\n };\n\n return (event: ProgressEvent): void => {\n switch (event.kind) {\n case \"browser\":\n say(\"starting browser\");\n return;\n case \"sitemap\":\n if (event.source === null) say(\"no sitemap; following links\");\n else say(`sitemap ${event.source} (${plural(event.urls, \"page\")})`);\n return;\n case \"page\":\n queued = event.queued;\n say(`${counter(event.index, queued)} ${event.url}`);\n return;\n case \"checked\": {\n const head = counter(event.index, queued);\n if (event.error !== undefined) say(`${head} could not load: ${event.error}`);\n else if (event.violations === 0) say(`${head} ✓`);\n else say(`${head} ✗ ${plural(event.violations, \"violation\")}`);\n return;\n }\n case \"done\":\n say(`checked ${plural(event.checked, \"page\")}, ${event.skipped} skipped`);\n return;\n }\n };\n}\n\n/** Length as the terminal shows it, with ANSI sequences taken out. */\nfunction visibleLength(text: string): number {\n return text.replace(/\\x1b\\[[0-9;]*m/g, \"\").length;\n}\n\n/**\n * Shorten `text` to `room` characters by replacing its middle with `…`, so\n * both the host and the page's own name survive. Never shorter than a few\n * characters, however narrow the terminal.\n */\nfunction truncateMiddle(text: string, room: number): string {\n const max = Math.max(room, 8);\n if (text.length <= max) return text;\n const head = Math.ceil((max - 1) / 2);\n const tail = max - 1 - head;\n return `${text.slice(0, head)}…${text.slice(text.length - tail)}`;\n}\n"],"mappings":"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","names":["Command","outcome","crawl","buildProgram","buildProgram","Command"]}
|
package/dist/docmeta.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/docmeta.ts"],"sourcesContent":["/**\n * The `docmeta` bin: the metadata tool under the name it had before it became\n * `manni meta`. Same program, same options, same exit codes, so a script or\n * workflow written against `docmeta …` keeps working. Only the usage line and\n * the stderr prefix say `docmeta`.\n */\nimport { buildProgram } from \"./meta/cli.js\";\nimport { runIfMain } from \"./shared/run.js\";\n\nrunIfMain(import.meta.url, () => buildProgram().name(\"docmeta\"));\n"],"mappings":";;;;;;;;AASA,UAAU,YAAY,KAAK,MAAM,aAAa,EAAE,KAAK,SAAS,CAAC;","names":[]}
|