@mark1russell7/site-pages 0.2.10 → 0.2.12
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/chunks/build.js +1 -1
- package/build/chunks/data-stamp.js +1 -1
- package/build/chunks/freshness.d.ts +13 -1
- package/build/chunks/freshness.d.ts.map +1 -1
- package/build/chunks/freshness.js +25 -7
- package/build/chunks/freshness.js.map +1 -1
- package/build/cli.js +1 -1
- package/build/explorer/index.d.ts +2 -0
- package/build/explorer/index.d.ts.map +1 -1
- package/build/explorer/index.js +15 -3
- package/build/explorer/index.js.map +1 -1
- package/build/index.d.ts +2 -2
- package/build/index.js +2 -2
- package/build/vite.d.ts +1 -1
- package/build/vite.js +1 -1
- package/package.json +1 -1
package/build/chunks/build.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { C as readKpi, D as headingDate, E as headCommit, F as versionOfTag, M as compareVersions, N as kindOf, O as isShallow, P as parseVersion, T as gitTagDates, _ as KPI_FILE, d as escapeHtml, f as inlineMarkdown, h as plural, j as npmPublishTimes, k as originRepository, m as listText, p as link, y as KpiError } from "./freshness.js";
|
|
2
2
|
import { stripTypeScriptTypes } from "node:module";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, isAbsolute, join, posix, resolve } from "node:path";
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { d as escapeHtml, m as listText, p as link } from "./freshness.js";
|
|
2
2
|
// src/render/data-stamp.ts
|
|
3
3
|
/** This function gives an engine and its version in the short form, without the npm scope. */
|
|
4
4
|
function engineText(name, version) {
|
|
@@ -292,6 +292,18 @@ declare function parseDataStamps(raw: unknown): DataStampsParse;
|
|
|
292
292
|
declare function minorsBehind(used: string, latest: string): number;
|
|
293
293
|
/** This function gives the newest stable version of a package on npm at a time, or undefined when npm has none. */
|
|
294
294
|
declare function latestAt(times: readonly NpmVersionTime[], name: string, date: string): string | undefined;
|
|
295
|
+
/** One schedule of a workflow. */
|
|
296
|
+
interface CronLine {
|
|
297
|
+
/** The number of the line in the file, from 1. */
|
|
298
|
+
readonly line: number;
|
|
299
|
+
/** The cron text, with no quotes and no comment. */
|
|
300
|
+
readonly cron: string;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* This function gives each line `cron:` of a workflow. It is the one reader of these lines: the freshness gate and the rule `runner-budget` of conventions use it.
|
|
304
|
+
* It skips a comment line. It reads a quoted key, a list item, a quoted value and a comment at the end of the line.
|
|
305
|
+
*/
|
|
306
|
+
declare function cronLines(workflow: string): CronLine[];
|
|
295
307
|
/**
|
|
296
308
|
* This function applies the rules of the gate to the stamps.
|
|
297
309
|
*
|
|
@@ -302,5 +314,5 @@ declare function latestAt(times: readonly NpmVersionTime[], name: string, date:
|
|
|
302
314
|
* - A fixed study has no age limit and no limit of the engines, because it tells about the versions that it names.
|
|
303
315
|
*/
|
|
304
316
|
declare function checkFreshness(stamps: DataStamps, options: FreshnessOptions): FreshnessCheck;
|
|
305
|
-
export {
|
|
317
|
+
export { CheckState as A, OpenWorkTotals as B, kpiProblems as C, BoardIssue as D, writeKpi as E, KpiFile as F, StatusClass as G, ReleaseChange as H, KpiMeasure as I, Link as L, GitHubRelease as M, GitHubReleases as N, BoardItem as O, KpiEngine as P, NpmPublishTimes as R, kpiFile as S, readKpi as T, ReleaseKind as U, Release as V, StatusBoardData as W, parseDataStamps as _, DataStamps as a, KpiError as b, FreshnessOptions as c, MAX_MINORS_BEHIND as d, PageStamp as f, minorsBehind as g, latestAt as h, DataRun as i, GitHubOpenWork as j, BoardPullRequest as k, MAX_DATA_AGE_DAYS as l, cronLines as m, DATA_STAMP_SCHEMA as n, DataStampsParse as o, checkFreshness as p, DataLimit as r, FreshnessCheck as s, CronLine as t, MAX_LIMIT_DAYS_WITHOUT_RULING as u, KPI_FILE as v, kpiText as w, KpiInput as x, KPI_FORMAT as y, NpmVersionTime as z };
|
|
306
318
|
//# sourceMappingURL=freshness.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"freshness.d.ts","names":[],"sources":["../../src/data/types.ts","../../src/data/kpi.ts","../../src/check/freshness.ts"],"mappings":";;;;;UAMiB;EACf;EACA;;;;;;KAWU;;UAGK;;EAEf;;EAEA;;EAEA;;;UAIe;EACf;;EAEA;EACA,MAAM;;EAEN,SAAS;;EAET,OAAO;;;UAIQ;EACf;EACA;;EAEA;;EAEA;EACA;EACA;;;KAIU;EAAmB;EAAiB,UAAU;;EAAsB;EAAkB;;;UAGjF;EACf;EACA;EACA;;;UAIe;EACf,OAAO;EACP;;;KAQU;;UAGK;EACf;EACA;;EAEA;EACA,aAAa;EACb;EACA;;EAEA;;EAEA;;EAEA;EACA,OAAO;;;KAIG;;UAGK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;;;UAIO;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;;;KAIU;EACN;EAAiB,cAAc;EAAoB,QAAQ;EAAc,QAAQ;;EACjF;EAAkB;;;UAGP;;EAEf;EACA;EACA;;EAEA;;;UAIe;;EAEf;EACA;;;UAIe;EACf;;EAEA;;EAEA;;EAEA;EACA,UAAU;;EAEV,UAAU;;;UAIK;;EAEf;;EAEA;;EAEA;IAAU;IAAwB;;EAClC,OAAO;EACP,cAAc;EACd,QAAQ;;EAER;IAAU;IAAoB;IAAiB,SAAS;;;EAExD,MAAM;;;cCvKK;;cAGA;;KAGD,WAAW,KAAK;;cAef,iBAAiB;WACnB;EAET,YAAY;;;;;;;;iBA4CE,YAAY,gBAAgB;;;;;;iBAgC5B,QAAQ,OAAO,UAAU,eAAe;;iBASxC,QAAQ,MAAM;;;;;;iBASd,QAAQ,cAAc,eAAe;;;;;;iBAkBrC,SAAS,aAAa,OAAO,UAAU;;cCnI1C;;cAGA;;cAGA;;cAGA;;UAKI;WACN;WACA;;WAEA;;WAEA,SAAS,SAAS;;;UAIZ;;WAEN;;WAEA;;WAEA;;WAEA;;;UAIM;WACN;;WAEA,eAAe;;WAEf,WAAW;;WAEX;;WAEA,QAAQ;;;UAIF;WACN,eAAe;WACf,gBAAgB;;;KAIf;WAA6B;WAAmB,QAAQ;;WAA0B;WAAoB;;;UAGjG;;WAEN;;WAEA,gBAAgB;;WAEhB;;WAEA;;WAEA,YAAY,SAAS;;;UAIf;;WAEN;;WAEA;;;;;;iBAsDK,gBAAgB,eAAe;;iBAwB/B,aAAa,cAAc;;iBAS3B,SAAS,gBAAgB,kBAAkB,cAAc;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"freshness.d.ts","names":[],"sources":["../../src/data/types.ts","../../src/data/kpi.ts","../../src/check/freshness.ts"],"mappings":";;;;;UAMiB;EACf;EACA;;;;;;KAWU;;UAGK;;EAEf;;EAEA;;EAEA;;;UAIe;EACf;;EAEA;EACA,MAAM;;EAEN,SAAS;;EAET,OAAO;;;UAIQ;EACf;EACA;;EAEA;;EAEA;EACA;EACA;;;KAIU;EAAmB;EAAiB,UAAU;;EAAsB;EAAkB;;;UAGjF;EACf;EACA;EACA;;;UAIe;EACf,OAAO;EACP;;;KAQU;;UAGK;EACf;EACA;;EAEA;EACA,aAAa;EACb;EACA;;EAEA;;EAEA;;EAEA;EACA,OAAO;;;KAIG;;UAGK;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,QAAQ;;;UAIO;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;;;KAIU;EACN;EAAiB,cAAc;EAAoB,QAAQ;EAAc,QAAQ;;EACjF;EAAkB;;;UAGP;;EAEf;EACA;EACA;;EAEA;;;UAIe;;EAEf;EACA;;;UAIe;EACf;;EAEA;;EAEA;;EAEA;EACA,UAAU;;EAEV,UAAU;;;UAIK;;EAEf;;EAEA;;EAEA;IAAU;IAAwB;;EAClC,OAAO;EACP,cAAc;EACd,QAAQ;;EAER;IAAU;IAAoB;IAAiB,SAAS;;;EAExD,MAAM;;;cCvKK;;cAGA;;KAGD,WAAW,KAAK;;cAef,iBAAiB;WACnB;EAET,YAAY;;;;;;;;iBA4CE,YAAY,gBAAgB;;;;;;iBAgC5B,QAAQ,OAAO,UAAU,eAAe;;iBASxC,QAAQ,MAAM;;;;;;iBASd,QAAQ,cAAc,eAAe;;;;;;iBAkBrC,SAAS,aAAa,OAAO,UAAU;;cCnI1C;;cAGA;;cAGA;;cAGA;;UAKI;WACN;WACA;;WAEA;;WAEA,SAAS,SAAS;;;UAIZ;;WAEN;;WAEA;;WAEA;;WAEA;;;UAIM;WACN;;WAEA,eAAe;;WAEf,WAAW;;WAEX;;WAEA,QAAQ;;;UAIF;WACN,eAAe;WACf,gBAAgB;;;KAIf;WAA6B;WAAmB,QAAQ;;WAA0B;WAAoB;;;UAGjG;;WAEN;;WAEA,gBAAgB;;WAEhB;;WAEA;;WAEA,YAAY,SAAS;;;UAIf;;WAEN;;WAEA;;;;;;iBAsDK,gBAAgB,eAAe;;iBAwB/B,aAAa,cAAc;;iBAS3B,SAAS,gBAAgB,kBAAkB,cAAc;;UAqDxD;;WAEN;;WAEA;;;;;;iBAOK,UAAU,mBAAmB;;;;;;;;;;iBAsD7B,eAAe,QAAQ,YAAY,SAAS,mBAAmB"}
|
|
@@ -584,18 +584,36 @@ function cronDays(line, from, days) {
|
|
|
584
584
|
}
|
|
585
585
|
return starts;
|
|
586
586
|
}
|
|
587
|
-
/**
|
|
588
|
-
function
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
587
|
+
/**
|
|
588
|
+
* This function gives each line `cron:` of a workflow. It is the one reader of these lines: the freshness gate and the rule `runner-budget` of conventions use it.
|
|
589
|
+
* It skips a comment line. It reads a quoted key, a list item, a quoted value and a comment at the end of the line.
|
|
590
|
+
*/
|
|
591
|
+
function cronLines(workflow) {
|
|
592
|
+
return workflow.split(/\r?\n/).flatMap((raw, index) => {
|
|
593
|
+
const text = raw.trim().replace(/^- */, "");
|
|
594
|
+
const key = [
|
|
595
|
+
"cron:",
|
|
596
|
+
"\"cron\":",
|
|
597
|
+
"'cron':"
|
|
598
|
+
].find((form) => text.startsWith(form));
|
|
599
|
+
if (key === void 0) return [];
|
|
600
|
+
const rest = text.slice(key.length);
|
|
601
|
+
const comment = rest.search(/\s#/);
|
|
602
|
+
const value = (comment >= 0 ? rest.slice(0, comment) : rest).trim();
|
|
603
|
+
const quote = value.charAt(0);
|
|
604
|
+
const quoted = value.length >= 2 && (quote === "\"" || quote === "'") && value.endsWith(quote);
|
|
605
|
+
return [{
|
|
606
|
+
line: index + 1,
|
|
607
|
+
cron: quoted ? value.slice(1, -1).trim() : value
|
|
608
|
+
}];
|
|
609
|
+
});
|
|
592
610
|
}
|
|
593
611
|
/**
|
|
594
612
|
* This function gives the largest gap between the scheduled starts of a workflow, in days. The gap counts from the first start of a day.
|
|
595
613
|
* It gives a text in place of the gap for a workflow with no schedule, and for a line that it cannot read. The text names the line, and the gate fails on it.
|
|
596
614
|
*/
|
|
597
615
|
function scheduleGapDays(workflow) {
|
|
598
|
-
const lines = workflow.
|
|
616
|
+
const lines = cronLines(workflow).map((item) => item.cron);
|
|
599
617
|
if (lines.length === 0) return "the workflow has no line `cron:`";
|
|
600
618
|
const from = Date.UTC(2027, 0, 1);
|
|
601
619
|
const span = 731;
|
|
@@ -736,6 +754,6 @@ async function runFreshnessCli(argv, io, fetcher) {
|
|
|
736
754
|
io.stdout(`The data stamps of ${parsed.stamps.pages.length} pages pass.\n`);
|
|
737
755
|
return 0;
|
|
738
756
|
}
|
|
739
|
-
export {
|
|
757
|
+
export { NPM_REGISTRY as A, readKpi as C, headingDate as D, headCommit as E, versionOfTag as F, compareVersions as M, kindOf as N, isShallow as O, parseVersion as P, kpiText as S, gitTagDates as T, KPI_FILE as _, checkFreshness as a, kpiFile as b, minorsBehind as c, escapeHtml as d, inlineMarkdown as f, safeUrl as g, plural as h, MAX_MINORS_BEHIND as i, npmPublishTimes as j, originRepository as k, parseDataStamps as l, listText as m, MAX_DATA_AGE_DAYS as n, cronLines as o, link as p, MAX_LIMIT_DAYS_WITHOUT_RULING as r, latestAt as s, DATA_STAMP_SCHEMA as t, runFreshnessCli as u, KPI_FORMAT as v, writeKpi as w, kpiProblems as x, KpiError as y };
|
|
740
758
|
|
|
741
759
|
//# sourceMappingURL=freshness.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"freshness.js","names":[],"sources":["../../src/data/versions.ts","../../src/data/npm.ts","../../src/data/git.ts","../../src/data/kpi.ts","../../src/render/html.ts","../../src/check/freshness.ts"],"sourcesContent":["/**\n * Versions: the SemVer parser, the sort, the kind of a version and the version of a git tag.\n */\n\nimport type { ReleaseKind } from \"./types.ts\";\n\n/** The parts of a SemVer 2.0.0 version. */\nexport interface ParsedVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;\n\n/** This function gives the parts of a version, or null when the text is not a SemVer version. */\nexport function parseVersion(version: string): ParsedVersion | null {\n const match = SEMVER.exec(version);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\n/**\n * This function compares two versions by the SemVer precedence. It gives a negative number when `a`\n * is older, a positive number when `a` is newer, and 0 for the same version. A text that is not a\n * version comes before each version.\n */\nexport function compareVersions(a: string, b: string): number {\n const x = parseVersion(a);\n const y = parseVersion(b);\n if (!x || !y) return x ? 1 : y ? -1 : a.localeCompare(b);\n const core = x.major - y.major || x.minor - y.minor || x.patch - y.patch;\n if (core !== 0) return core;\n // A prerelease comes before its release: 1.0.0-rc.1 < 1.0.0\n if (x.prerelease.length === 0 || y.prerelease.length === 0) return y.prerelease.length - x.prerelease.length;\n for (let index = 0; index < Math.max(x.prerelease.length, y.prerelease.length); index++) {\n const p = x.prerelease[index];\n const q = y.prerelease[index];\n if (p === undefined) return -1;\n if (q === undefined) return 1;\n if (p === q) continue;\n const pNumber = /^\\d+$/.test(p);\n const qNumber = /^\\d+$/.test(q);\n if (pNumber && qNumber) return Number(p) - Number(q);\n if (pNumber !== qNumber) return pNumber ? -1 : 1;\n return p < q ? -1 : 1;\n }\n return 0;\n}\n\n/**\n * This function gives the kind of a version. The oldest version of the list is \"first\". The caller\n * tells if the version is the oldest.\n */\nexport function kindOf(version: string, oldest: boolean): ReleaseKind {\n if (oldest) return \"first\";\n const parsed = parseVersion(version);\n if (!parsed) return \"patch\";\n if (parsed.major > 0 && parsed.minor === 0 && parsed.patch === 0) return \"major\";\n return parsed.patch === 0 ? \"minor\" : \"patch\";\n}\n\n/** The version of a git tag, and the package that the tag names (null for a tag like `v1.2.3`). */\nexport interface TagVersion {\n version: string;\n package: string | null;\n}\n\n/**\n * This function reads the version of a git tag. It knows `1.2.3`, `v1.2.3` and the tags of Changesets:\n * `name@1.2.3` and `@scope/name@1.2.3`. It gives null for another tag.\n */\nexport function versionOfTag(tag: string): TagVersion | null {\n const match = /^(?:(.+)@)?v?(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.+-]*)?)$/.exec(tag.trim());\n if (!match || match[2] === undefined || !parseVersion(match[2])) return null;\n return { version: match[2], package: match[1] ?? null };\n}\n","/**\n * The npm source: the publication time of each version of some packages. The release data uses\n * these times when git and GitHub give no date for a version.\n */\n\nimport type { NpmPublishTimes, NpmVersionTime } from \"./types.ts\";\n\n/** The public npm registry. */\nexport const NPM_REGISTRY = \"https://registry.npmjs.org\";\n\n/** The options of `npmPublishTimes`. */\nexport interface NpmOptions {\n /** The npm names of the packages, or a scope (for example `@procedures`) for all the packages of the scope. */\n packages: readonly string[];\n /** The `fetch` function. The default is the global `fetch`. */\n fetch?: typeof fetch;\n registry?: string;\n /** The time limit of each request, in milliseconds. The default is 15000. */\n timeoutMs?: number;\n}\n\ntype Json = Record<string, unknown>;\nconst object = (value: unknown): Json => (value !== null && typeof value === \"object\" ? (value as Json) : {});\n\nfunction message(error: unknown): string {\n if (object(error)[\"name\"] === \"TimeoutError\") return \"npm did not answer in time\";\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * This function reads the publication time of each version of the packages from the npm registry.\n * A scope (`@name`) gives each package of the scope. It does not throw. Each failure gives a\n * message in `problems`.\n */\nexport async function npmPublishTimes(options: NpmOptions): Promise<NpmPublishTimes> {\n const { registry = NPM_REGISTRY, timeoutMs = 15_000 } = options;\n const fetcher = options.fetch ?? globalThis.fetch;\n const problems: string[] = [];\n const times: NpmVersionTime[] = [];\n if (typeof fetcher !== \"function\") return { times, problems: [\"this Node has no fetch\"] };\n const get = async (url: string): Promise<unknown> => {\n const response = await fetcher(url, { headers: { accept: \"application/json\" }, signal: AbortSignal.timeout(timeoutMs) });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n return response.json();\n };\n\n const names = new Set<string>();\n for (const entry of options.packages.map((name) => name.trim()).filter(Boolean)) {\n if (!/^@[^/]+$/.test(entry)) {\n names.add(entry);\n continue;\n }\n try {\n const found = object(await get(`${registry}/-/v1/search?text=scope:${encodeURIComponent(entry.slice(1))}&size=250`));\n const objects = Array.isArray(found[\"objects\"]) ? found[\"objects\"] : [];\n const before = names.size;\n for (const item of objects) {\n const name = object(object(item)[\"package\"])[\"name\"];\n if (typeof name === \"string\" && name.startsWith(`${entry}/`)) names.add(name);\n }\n if (names.size === before) problems.push(`npm has no package in the scope ${entry}`);\n } catch (error) {\n problems.push(`npm did not give the packages of ${entry}: ${message(error)}`);\n }\n }\n\n // Four requests at a time\n const queue = [...names].sort();\n const worker = async (): Promise<void> => {\n for (let name = queue.shift(); name !== undefined; name = queue.shift()) {\n try {\n const packument = object(await get(`${registry}/${name.replaceAll(\"/\", \"%2f\")}`));\n const published = object(packument[\"versions\"]);\n for (const [version, date] of Object.entries(object(packument[\"time\"]))) {\n if (version === \"created\" || version === \"modified\" || typeof date !== \"string\") continue;\n if (!(version in published)) continue;\n times.push({ name, version, date });\n }\n } catch (error) {\n problems.push(`npm did not give the versions of ${name}: ${message(error)}`);\n }\n }\n };\n await Promise.all(Array.from({ length: 4 }, worker));\n times.sort((a, b) => a.name.localeCompare(b.name) || a.date.localeCompare(b.date));\n return { times, problems };\n}\n","/**\n * The git source: the tags with their dates, the commit of the build and the GitHub remote. Each\n * function gives an empty result when git or the repository is not available.\n */\n\nimport { execFileSync } from \"node:child_process\";\n\n/** A git tag and the ISO date of its creation. */\nexport interface TagDate {\n tag: string;\n date: string;\n}\n\n/** This function starts git in a folder and gives its output, or null when git fails. */\nexport function git(repoDir: string, ...args: string[]): string | null {\n try {\n return execFileSync(\"git\", args, { cwd: repoDir, encoding: \"utf8\", stdio: [\"ignore\", \"pipe\", \"ignore\"], windowsHide: true });\n } catch {\n return null;\n }\n}\n\n/** This function tells if the clone is shallow. A shallow clone has not all the tags and commits. */\nexport function isShallow(repoDir: string): boolean {\n return git(repoDir, \"rev-parse\", \"--is-shallow-repository\")?.trim() === \"true\";\n}\n\n/** This function gives each tag of the repository with its date. An annotated tag has its own date. */\nexport function gitTagDates(repoDir: string): TagDate[] {\n const output = git(repoDir, \"for-each-ref\", \"--format=%(refname:strip=2) %(creatordate:iso-strict)\", \"refs/tags\");\n if (!output) return [];\n const tags: TagDate[] = [];\n for (const line of output.split(/\\r?\\n/)) {\n const match = /^(\\S+) (\\S+)$/.exec(line.trim());\n if (match?.[1] && match[2]) tags.push({ tag: match[1], date: match[2] });\n }\n return tags;\n}\n\n/**\n * This function gives the date of the oldest commit that added a version heading to a changelog,\n * or null. The path of the changelog starts at `repoDir`.\n */\nexport function headingDate(repoDir: string, version: string, file: string): string | null {\n const output = git(repoDir, \"log\", \"--format=%cI\", `-S## ${version}`, \"--\", file);\n const dates = (output ?? \"\").trim().split(/\\r?\\n/).filter(Boolean);\n return dates[dates.length - 1] ?? null;\n}\n\n/** This function gives the full SHA of `HEAD`, or null. */\nexport function headCommit(repoDir: string): string | null {\n const sha = git(repoDir, \"rev-parse\", \"HEAD\")?.trim();\n return sha && /^[0-9a-f]{40}$/.test(sha) ? sha : null;\n}\n\n/** This function gives \"owner/name\" of the GitHub remote \"origin\", or null. */\nexport function originRepository(repoDir: string): string | null {\n const url = git(repoDir, \"remote\", \"get-url\", \"origin\")?.trim() ?? \"\";\n const match = /github\\.com[:/]([^/]+)\\/(.+?)(?:\\.git)?\\/?$/.exec(url);\n return match ? `${match[1]}/${match[2]}` : null;\n}\n","/**\n * The file `kpi.json` at the root of a site, format `kpi/1`. A reader outside the site takes the measures of the project\n * from this file. Thus a number on a progress page comes from a record and not from a person.\n *\n * The field `at` is the time of the data and not the time of the build. Thus the writer has no default for it.\n * A measure can have its own `at` when its data is from another time than the rest of the file.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { KpiEngine, KpiFile, KpiMeasure } from \"./types.ts\";\n\n/** The name of the format. A new format gets a new name, so that an old reader refuses it. */\nexport const KPI_FORMAT = \"kpi/1\";\n\n/** The name of the file at the root of the built site. */\nexport const KPI_FILE = \"kpi.json\";\n\n/** The data of `kpi.json`, without the name of the format. */\nexport type KpiInput = Omit<KpiFile, \"format\">;\n\n/** The form of a project and a measure. A double hyphen separates fields in the file name of a reading. */\nconst SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/** The form of a time in UTC, with or without seconds. */\nconst UTC_TIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?Z$/;\n\n/** The form of a full commit. */\nconst COMMIT = /^[0-9a-f]{40}$/;\n\n/** The clock difference between two computers that the check accepts, in milliseconds. */\nconst CLOCK_MARGIN = 5 * 60 * 1000;\n\n/** An error in the data of `kpi.json`. The field `problems` has one line for each fault. */\nexport class KpiError extends Error {\n readonly problems: readonly string[];\n\n constructor(problems: readonly string[]) {\n super(`${KPI_FILE} is not correct: ${problems.join(\" \")}`);\n this.name = \"KpiError\";\n this.problems = problems;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isText = (value: unknown): value is string => typeof value === \"string\" && value.trim() !== \"\";\n\n/** This function gives the fault of a time of the data, or an empty list. The name tells which field it is. */\nfunction timeProblems(at: unknown, name: string, now: number): string[] {\n if (typeof at !== \"string\" || !UTC_TIME.test(at) || Number.isNaN(Date.parse(at))) return [`${name} is not a time in UTC.`];\n return Date.parse(at) > now + CLOCK_MARGIN ? [`The time of the data ${at} is after the time of the check.`] : [];\n}\n\n/** This function gives the faults of one measure. */\nfunction measureProblems(value: unknown, index: number, seen: Set<string>, now: number): string[] {\n if (!isRecord(value)) return [`Measure ${index} is not an object.`];\n const { id, value: amount, unit, at } = value;\n const problems: string[] = [];\n if (typeof id !== \"string\" || !SLUG.test(id)) problems.push(`Measure ${index} has no id of lowercase words with single hyphens.`);\n else if (seen.has(id)) problems.push(`The id ${id} occurs two times.`);\n else seen.add(id);\n if (typeof amount !== \"number\" || !Number.isFinite(amount)) problems.push(`Measure ${index} has no finite number as its value.`);\n if (unit !== undefined && !isText(unit)) problems.push(`Measure ${index} has a unit that is not a text.`);\n if (at !== undefined) problems.push(...timeProblems(at, `The field at of measure ${index}`, now));\n return problems;\n}\n\n/** This function gives the faults of the list of engines. */\nfunction engineProblems(value: unknown): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) return [\"The field engines is not a list.\"];\n return value.flatMap((engine: unknown, index) => (isRecord(engine) && isText(engine[\"name\"]) && isText(engine[\"version\"]) ? [] : [`Engine ${index} has no name and version.`]));\n}\n\n/**\n * This function gives the faults of a parsed `kpi.json`, or an empty list.\n *\n * @param value - The parsed file.\n * @param now - The time of the check, in milliseconds. A time of the data after this time is a fault.\n */\nexport function kpiProblems(value: unknown, now: number = Date.now()): string[] {\n if (!isRecord(value)) return [\"The file is not an object.\"];\n const problems: string[] = [];\n if (value[\"format\"] !== KPI_FORMAT) problems.push(`The format is not ${KPI_FORMAT}.`);\n const { project, at, commit, measures } = value;\n if (typeof project !== \"string\" || !SLUG.test(project)) problems.push(\"The project is not lowercase words with single hyphens.\");\n problems.push(...timeProblems(at, \"The field at\", now));\n if (typeof commit !== \"string\" || !COMMIT.test(commit)) problems.push(\"The commit is not a full commit.\");\n if (!Array.isArray(measures) || measures.length === 0) problems.push(\"The file has no measures.\");\n else {\n const seen = new Set<string>();\n problems.push(...measures.flatMap((measure: unknown, index) => measureProblems(measure, index, seen, now)));\n }\n problems.push(...engineProblems(value[\"engines\"]));\n return problems;\n}\n\n/** This function gives a copy of a measure with only its known fields. */\nfunction cleanMeasure({ id, value, unit, at }: KpiMeasure): KpiMeasure {\n return { id, value, ...(unit === undefined ? {} : { unit }), ...(at === undefined ? {} : { at }) };\n}\n\n/** This function gives a copy of an engine with only its known fields. */\nfunction cleanEngine({ name, version }: KpiEngine): KpiEngine {\n return { name, version };\n}\n\n/**\n * This function gives the checked content of `kpi.json`. The file has only its known fields, in a fixed order.\n *\n * @throws KpiError when the data is not correct\n */\nexport function kpiFile(input: KpiInput, now?: number): KpiFile {\n const problems = kpiProblems({ format: KPI_FORMAT, ...input }, now);\n if (problems.length > 0) throw new KpiError(problems);\n const { project, at, commit, measures, engines } = input;\n const file: KpiFile = { format: KPI_FORMAT, project, at, commit, measures: measures.map(cleanMeasure) };\n return engines === undefined ? file : { ...file, engines: engines.map(cleanEngine) };\n}\n\n/** This function gives the text of `kpi.json`. */\nexport function kpiText(file: KpiFile): string {\n return `${JSON.stringify(file, null, 2)}\\n`;\n}\n\n/**\n * This function reads the text of a `kpi.json`.\n *\n * @throws KpiError when the text is not correct\n */\nexport function readKpi(text: string, now?: number): KpiFile {\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch (error) {\n throw new KpiError([`The file is not JSON: ${error instanceof Error ? error.message : String(error)}`]);\n }\n const problems = kpiProblems(value, now);\n if (problems.length > 0) throw new KpiError(problems);\n const { project, at, commit, measures, engines } = value as KpiFile;\n return kpiFile(engines === undefined ? { project, at, commit, measures } : { project, at, commit, measures, engines }, now);\n}\n\n/**\n * This function writes `kpi.json` into the built output folder of a site, and gives the path of the file.\n *\n * @throws KpiError when the data is not correct\n */\nexport function writeKpi(out: string, input: KpiInput, now?: number): string {\n const text = kpiText(kpiFile(input, now));\n mkdirSync(out, { recursive: true });\n const file = join(out, KPI_FILE);\n writeFileSync(file, text);\n return file;\n}\n","/**\n * The HTML helpers of the pages: the escape functions and a small inline Markdown renderer.\n */\n\nconst ESCAPES: Record<string, string> = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" };\n\n/** This function escapes a text for HTML content and for an attribute value in double quotes. */\nexport function escapeHtml(text: string): string {\n return String(text).replace(/[&<>\"']/g, (char) => ESCAPES[char] ?? char);\n}\n\n/**\n * This function removes the control characters and the spaces (U+0000 to U+0020) at the two ends\n * of a text. A loop does it, because the regular expression `[\\u0000- ]+$` backtracks. For a long\n * run of these characters, its time grows with the square of the length.\n */\nfunction trimControl(text: string): string {\n let start = 0;\n let end = text.length;\n while (start < end && text.charCodeAt(start) <= 0x20) start++;\n while (end > start && text.charCodeAt(end - 1) <= 0x20) end--;\n return text.slice(start, end);\n}\n\n/**\n * This function gives a URL that a link can hold, or null. It accepts `http:`, `https:` and\n * `mailto:` URLs, and relative URLs. It refuses each other scheme, for example `javascript:`.\n *\n * The URL parser of a browser removes each tab and line break, and the control characters and\n * spaces at the two ends. This function removes them before the scheme check, as the browser does.\n * Thus a control character before `javascript:` does not hide the scheme.\n */\nexport function safeUrl(url: string): string | null {\n const trimmed = trimControl(url.trim().replace(/[\\t\\n\\r]/g, \"\"));\n if (/^(?:https?:|mailto:)/i.test(trimmed)) return trimmed;\n // A browser reads \"\\\" as \"/\" in a URL of the page, so \"\\\\host\" and \"/\\host\" go to a different host, as \"//host\" does\n if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || /^[/\\\\]{2}/.test(trimmed)) return null;\n return trimmed;\n}\n\n/** This function gives an `<a>` element, or the escaped text when the URL is not safe. */\nexport function link(url: string, html: string, attributes = \"\"): string {\n const href = safeUrl(url);\n return href === null ? html : `<a href=\"${escapeHtml(href)}\"${attributes ? ` ${attributes}` : \"\"}>${html}</a>`;\n}\n\n/** The emphasis of a text without code spans or links. The text is already escaped. */\nfunction emphasis(escaped: string): string {\n return escaped\n .replace(/\\*\\*([^*]+?)\\*\\*/g, \"<strong>$1</strong>\")\n .replace(/(^|[^\\w*])\\*([^*\\s][^*]*?)\\*(?![\\w*])/g, \"$1<em>$2</em>\")\n .replace(/(^|[^\\w])_([^_\\s][^_]*?)_(?![\\w])/g, \"$1<em>$2</em>\");\n}\n\nconst INLINE = \"`([^`]+)`|\\\\[((?:[^\\\\]`]|`[^`]*`)+)\\\\]\\\\(([^)\\\\s]+)\\\\)\";\n\n/**\n * This function renders inline Markdown as HTML: code spans, links, strong text and emphasis. It\n * escapes all other text, so the result is safe.\n */\nexport function inlineMarkdown(markdown: string): string {\n const text = String(markdown ?? \"\");\n // A new expression for each call: the text of a link is rendered with a recursive call\n const pattern = new RegExp(INLINE, \"g\");\n let html = \"\";\n let last = 0;\n for (let match = pattern.exec(text); match; match = pattern.exec(text)) {\n html += emphasis(escapeHtml(text.slice(last, match.index)));\n if (match[1] !== undefined) html += `<code>${escapeHtml(match[1])}</code>`;\n else html += link(match[3] ?? \"\", inlineMarkdown(match[2] ?? \"\"));\n last = match.index + match[0].length;\n }\n return html + emphasis(escapeHtml(text.slice(last)));\n}\n\n/** This function gives \"1 item\" or \"2 items\". */\nexport function plural(count: number, word: string, many = `${word}s`): string {\n return `${count} ${count === 1 ? word : many}`;\n}\n\n/** This function gives \"a\", \"a and b\" or \"a, b and c\". */\nexport function listText(parts: readonly string[]): string {\n if (parts.length <= 1) return parts.join(\"\");\n return `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`;\n}\n","/**\n * The freshness gate of a measured page. A site keeps a file of data stamps.\n * Each stamp names the page, its runs, their dates and their engine versions.\n * The gate fails on a page with no versions or no run date, and on old data with no newer run in flight.\n * The gate also fails on a run that started behind the engines on npm.\n * A fixed study has no age limit. A page with a longer limit names the reason and the scheduled workflow that meets the limit.\n * This file imports only Node.js and the folder `data`, so `reusable-pages.yml` starts it with no npm release of the package.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { npmPublishTimes } from \"../data/npm.ts\";\nimport type { NpmVersionTime } from \"../data/types.ts\";\nimport { compareVersions, parseVersion } from \"../data/versions.ts\";\nimport type { CheckIo } from \"./check.ts\";\n\n/** The schema of a file of data stamps. */\nexport const DATA_STAMP_SCHEMA = \"data-stamp/1\";\n\n/** The largest age of the data of a page, in days, when no newer run is in flight. */\nexport const MAX_DATA_AGE_DAYS = 3;\n\n/** The most minor versions that an engine of a run can be behind npm at the start of the run. */\nexport const MAX_MINORS_BEHIND = 1;\n\n/** The longest limit of a page, in days, with no ruling for that site. */\nexport const MAX_LIMIT_DAYS_WITHOUT_RULING = 14;\n\nconst DAY_MS = 86_400_000;\n\n/** One run that gives the data of a page. */\nexport interface DataRun {\n readonly id: string;\n readonly url: string;\n /** The ISO time of the start of the run. */\n readonly date: string;\n /** The version of each engine of the run, by its npm name. */\n readonly engines: Readonly<Record<string, string>>;\n}\n\n/** The age limit of one page, in place of `MAX_DATA_AGE_DAYS`. */\nexport interface DataLimit {\n /** The largest age of the data, in days. */\n readonly days: number;\n /** The reason for the limit, as one sentence. The page shows it. */\n readonly reason: string;\n /** The path of the workflow from the root of the repository. Its schedule must meet the limit. */\n readonly workflow: string;\n /** The link to the public ruling. A limit over `MAX_LIMIT_DAYS_WITHOUT_RULING` needs it. */\n readonly ruling?: string;\n}\n\n/** The stamp of one measured page. */\nexport interface PageStamp {\n readonly page: string;\n /** Each run that gives data to the page. */\n readonly runs: readonly DataRun[];\n /** The run on newer engines that is in progress. */\n readonly inFlight?: DataRun;\n /** The page shows a fixed study of the versions of its runs, so its data has no age limit. It makes no claim about a newer release. */\n readonly study?: true;\n /** The age limit of this page, in place of the default. */\n readonly limit?: DataLimit;\n}\n\n/** The content of a file of data stamps. */\nexport interface DataStamps {\n readonly schema: typeof DATA_STAMP_SCHEMA;\n readonly pages: readonly PageStamp[];\n}\n\n/** The result of `parseDataStamps`. */\nexport type DataStampsParse = { readonly ok: true; readonly stamps: DataStamps } | { readonly ok: false; readonly faults: readonly string[] };\n\n/** The options of `checkFreshness`. */\nexport interface FreshnessOptions {\n /** The ISO time of the check. */\n readonly now: string;\n /** The publication times of the engines on npm. */\n readonly times: readonly NpmVersionTime[];\n /** The limit of the age. The default is `MAX_DATA_AGE_DAYS`. */\n readonly maxAgeDays?: number;\n /** The limit of the minor versions. The default is `MAX_MINORS_BEHIND`. */\n readonly maxMinorsBehind?: number;\n /** The schedule of each workflow of a limit. A number is the largest gap between its starts in days. A text tells why the gate cannot read it. */\n readonly schedules?: Readonly<Record<string, number | string>>;\n}\n\n/** The result of `checkFreshness`. */\nexport interface FreshnessCheck {\n /** Each break of a rule. One fault fails the gate. */\n readonly faults: readonly string[];\n /** Each rule that the gate could not run, with the reason. */\n readonly notRun: readonly string[];\n}\n\nconst record = (value: unknown): Record<string, unknown> | null => (value !== null && typeof value === \"object\" && !Array.isArray(value) ? (value as Record<string, unknown>) : null);\n\n/** This function gives the faults of one run of a stamp. */\nfunction runFaults(raw: unknown, at: string): string[] {\n const run = record(raw);\n if (run === null) return [`${at}: a run is not an object.`];\n const faults: string[] = [];\n if (typeof run[\"id\"] !== \"string\" || run[\"id\"] === \"\") faults.push(`${at}: a run has no id.`);\n const label = `${at}, run ${String(run[\"id\"])}`;\n if (typeof run[\"url\"] !== \"string\" || !run[\"url\"].startsWith(\"https://\")) faults.push(`${label}: the run has no https link.`);\n if (typeof run[\"date\"] !== \"string\" || !Number.isFinite(Date.parse(run[\"date\"]))) faults.push(`${label}: the run has no date.`);\n const engines = record(run[\"engines\"]);\n if (engines === null || Object.keys(engines).length === 0) return [...faults, `${label}: the run names no engine versions.`];\n for (const [name, version] of Object.entries(engines)) {\n if (typeof version !== \"string\" || parseVersion(version) === null) faults.push(`${label}: the version of ${name} is not a version.`);\n }\n return faults;\n}\n\n/** This function gives the faults of the age limit of one page. */\nfunction limitFaults(raw: unknown, at: string): string[] {\n const limit = record(raw);\n if (limit === null) return [`${at}: the limit is not an object.`];\n const faults: string[] = [];\n const days = limit[\"days\"];\n if (typeof days !== \"number\" || !Number.isFinite(days) || days <= 0) faults.push(`${at}: the limit has no count of days.`);\n if (typeof limit[\"reason\"] !== \"string\" || limit[\"reason\"].trim() === \"\") faults.push(`${at}: the limit has no reason.`);\n if (typeof limit[\"workflow\"] !== \"string\" || limit[\"workflow\"] === \"\") faults.push(`${at}: the limit names no workflow.`);\n const ruling = limit[\"ruling\"];\n if (ruling !== undefined && (typeof ruling !== \"string\" || !ruling.startsWith(\"https://\"))) faults.push(`${at}: the ruling of the limit has no https link.`);\n if (typeof days === \"number\" && days > MAX_LIMIT_DAYS_WITHOUT_RULING && ruling === undefined) {\n faults.push(`${at}: a limit over ${MAX_LIMIT_DAYS_WITHOUT_RULING} days needs a ruling for this site.`);\n }\n return faults;\n}\n\n/** This function gives the faults of the fields of a page that change the age rule. */\nfunction ageRuleFaults(page: Record<string, unknown>, at: string): string[] {\n const faults: string[] = [];\n const study = page[\"study\"];\n if (study !== undefined && study !== true) faults.push(`${at}: the field study is not true.`);\n if (study === true && page[\"limit\"] !== undefined) faults.push(`${at}: a fixed study has no limit.`);\n if (study === true && page[\"inFlight\"] !== undefined) faults.push(`${at}: a fixed study has no run in flight.`);\n if (page[\"limit\"] !== undefined) faults.push(...limitFaults(page[\"limit\"], at));\n return faults;\n}\n\n/**\n * This function reads the content of a file of data stamps. It gives each fault of the content, so a page with no versions\n * or no run date fails here.\n */\nexport function parseDataStamps(raw: unknown): DataStampsParse {\n const file = record(raw);\n if (file === null) return { ok: false, faults: [\"The file is not an object.\"] };\n if (file[\"schema\"] !== DATA_STAMP_SCHEMA) return { ok: false, faults: [`The schema is not ${DATA_STAMP_SCHEMA}.`] };\n const pages = file[\"pages\"];\n if (!Array.isArray(pages) || pages.length === 0) return { ok: false, faults: [\"The file has no pages.\"] };\n const faults: string[] = [];\n for (const item of pages) {\n const page = record(item);\n if (page === null || typeof page[\"page\"] !== \"string\" || page[\"page\"] === \"\") {\n faults.push(\"A stamp has no page.\");\n continue;\n }\n const at = page[\"page\"];\n const runs = page[\"runs\"];\n if (!Array.isArray(runs) || runs.length === 0) faults.push(`${at}: the page names no run.`);\n else for (const run of runs) faults.push(...runFaults(run, at));\n if (page[\"inFlight\"] !== undefined) faults.push(...runFaults(page[\"inFlight\"], `${at}, in flight`));\n faults.push(...ageRuleFaults(page, at));\n }\n return faults.length > 0 ? { ok: false, faults } : { ok: true, stamps: raw as DataStamps };\n}\n\n/** This function gives the count of minor versions from `used` to `latest`. A newer major version counts as no limit. */\nexport function minorsBehind(used: string, latest: string): number {\n const a = parseVersion(used);\n const b = parseVersion(latest);\n if (a === null || b === null) return Number.POSITIVE_INFINITY;\n if (a.major !== b.major) return b.major > a.major ? Number.POSITIVE_INFINITY : 0;\n return Math.max(0, b.minor - a.minor);\n}\n\n/** This function gives the newest stable version of a package on npm at a time, or undefined when npm has none. */\nexport function latestAt(times: readonly NpmVersionTime[], name: string, date: string): string | undefined {\n const limit = Date.parse(date);\n return times\n .filter((t) => t.name === name && Date.parse(t.date) <= limit && parseVersion(t.version)?.prerelease.length === 0)\n .map((t) => t.version)\n .sort(compareVersions)\n .at(-1);\n}\n\nconst ageInDays = (date: string, now: number): number => (now - Date.parse(date)) / DAY_MS;\n\n/** This function gives the values of one field of a cron line, or undefined for a form that it cannot read. */\nfunction cronValues(field: string, low: number, high: number): Set<number> | undefined {\n const values = new Set<number>();\n for (const part of field.split(\",\")) {\n const match = /^(\\*|\\d+(?:-\\d+)?)(?:\\/(\\d+))?$/.exec(part);\n if (match === null) return undefined;\n const [, range = \"\", step = \"1\"] = match;\n const [from = low, to = from] = range === \"*\" ? [low, high] : range.split(\"-\").map(Number);\n const by = Number(step);\n if (by <= 0 || from < low || to > high || from > to) return undefined;\n for (let value = from; value <= to; value += by) values.add(value);\n }\n return values;\n}\n\n/** This function gives the start of each day of a cron line, in a span of two years. It gives undefined for a line that it cannot read. */\nfunction cronDays(line: string, from: number, days: number): number[] | undefined {\n const fields = line.trim().split(/\\s+/);\n if (fields.length !== 5) return undefined;\n const [minute = \"\", hour = \"\", dayOfMonth = \"\", month = \"\", dayOfWeek = \"\"] = fields;\n const minutes = cronValues(minute, 0, 59);\n const hours = cronValues(hour, 0, 23);\n const monthDays = cronValues(dayOfMonth, 1, 31);\n const months = cronValues(month, 1, 12);\n const weekDays = cronValues(dayOfWeek, 0, 6);\n if (minutes === undefined || hours === undefined || monthDays === undefined || months === undefined || weekDays === undefined) return undefined;\n const firstTime = (Math.min(...hours) * 60 + Math.min(...minutes)) * 60_000;\n const starts: number[] = [];\n for (let day = 0; day < days; day += 1) {\n const time = from + day * DAY_MS;\n const date = new Date(time);\n if (!months.has(date.getUTCMonth() + 1)) continue;\n const onMonthDay = monthDays.has(date.getUTCDate());\n const onWeekDay = weekDays.has(date.getUTCDay());\n // A cron line that sets both day fields starts on a day that matches one of them.\n const both = dayOfMonth !== \"*\" && dayOfWeek !== \"*\";\n if (both ? onMonthDay || onWeekDay : onMonthDay && onWeekDay) starts.push(time + firstTime);\n }\n return starts;\n}\n\n/** This function gives the cron text of one line of a workflow in a list, or an empty list for another line. */\nfunction cronLine(line: string): string[] {\n const text = line.trim().replace(/^- */, \"\");\n if (!text.startsWith(\"cron:\")) return [];\n const value = text.slice(\"cron:\".length).split(\"#\")[0]?.trim() ?? \"\";\n return [value.replaceAll('\"', \"\").replaceAll(\"'\", \"\")];\n}\n\n/**\n * This function gives the largest gap between the scheduled starts of a workflow, in days. The gap counts from the first start of a day.\n * It gives a text in place of the gap for a workflow with no schedule, and for a line that it cannot read. The text names the line, and the gate fails on it.\n */\nexport function scheduleGapDays(workflow: string): number | string {\n const lines = workflow.split(\"\\n\").flatMap(cronLine);\n if (lines.length === 0) return \"the workflow has no line `cron:`\";\n const from = Date.UTC(2027, 0, 1);\n const span = 731;\n const starts: number[] = [];\n for (const line of lines) {\n const days = cronDays(line, from, span);\n if (days === undefined) return `the gate cannot read the line \\`cron: ${line}\\``;\n starts.push(...days);\n }\n if (starts.length < 2) return `the lines \\`cron: ${lines.join(\"`, `cron: \")}\\` give fewer than two starts in two years`;\n starts.sort((a, b) => a - b);\n let largest = 0;\n for (let index = 1; index < starts.length; index += 1) largest = Math.max(largest, ((starts[index] ?? 0) - (starts[index - 1] ?? 0)) / DAY_MS);\n return largest;\n}\n\n/** This function tells if a run uses a newer version of an engine than another run. */\nfunction hasNewerEngine(run: DataRun, than: DataRun): boolean {\n return Object.entries(run.engines).some(([name, version]) => {\n const old = than.engines[name];\n return old !== undefined && compareVersions(version, old) > 0;\n });\n}\n\n/**\n * This function applies the rules of the gate to the stamps.\n *\n * - The data of each page is at most `maxAgeDays` old, or a run on newer engines is in flight.\n * - The engines of the newest run are at most `maxMinorsBehind` behind npm at the start of that run.\n * - A run in flight has the same age limit, so an old stamp does not hold the gate open.\n * - A page with its own limit uses that limit, and the schedule of its workflow meets the limit.\n * - A fixed study has no age limit and no limit of the engines, because it tells about the versions that it names.\n */\nexport function checkFreshness(stamps: DataStamps, options: FreshnessOptions): FreshnessCheck {\n const { times, maxAgeDays: defaultAge = MAX_DATA_AGE_DAYS, maxMinorsBehind = MAX_MINORS_BEHIND, schedules = {} } = options;\n const now = Date.parse(options.now);\n const faults: string[] = [];\n const notRun: string[] = [];\n for (const stamp of stamps.pages) {\n for (const run of [...stamp.runs, ...(stamp.inFlight === undefined ? [] : [stamp.inFlight])]) {\n if (ageInDays(run.date, now) < 0) faults.push(`${stamp.page}: the run ${run.id} has a date after the check.`);\n }\n if (stamp.study === true) continue;\n const maxAgeDays = stamp.limit?.days ?? defaultAge;\n if (stamp.limit !== undefined) {\n const gap = schedules[stamp.limit.workflow];\n if (gap === undefined || typeof gap === \"string\") faults.push(`${stamp.page}: the limit of ${maxAgeDays} days has no schedule that the gate can read in ${stamp.limit.workflow}: ${gap ?? \"the check has no read of this workflow\"}.`);\n else if (gap > maxAgeDays) faults.push(`${stamp.page}: the schedule of ${stamp.limit.workflow} has a gap of ${gap.toFixed(1)} days, over the limit of ${maxAgeDays}.`);\n }\n const flight = stamp.inFlight;\n const flying = flight !== undefined && ageInDays(flight.date, now) <= maxAgeDays;\n if (flight !== undefined && !flying) faults.push(`${stamp.page}: the run ${flight.id} is in flight for more than ${maxAgeDays} days.`);\n for (const run of stamp.runs) {\n const age = ageInDays(run.date, now);\n if (age > maxAgeDays && !(flying && hasNewerEngine(flight, run))) {\n faults.push(`${stamp.page}: the run ${run.id} is ${age.toFixed(1)} days old, over the limit of ${maxAgeDays}, and no run on newer engines is in flight.`);\n }\n }\n const newest = flight ?? [...stamp.runs].sort((a, b) => Date.parse(a.date) - Date.parse(b.date)).at(-1);\n if (newest === undefined) continue;\n for (const [name, version] of Object.entries(newest.engines)) {\n const latest = latestAt(times, name, newest.date);\n if (latest === undefined) {\n notRun.push(`${stamp.page}: npm gives no version of ${name} at the start of the run ${newest.id}.`);\n } else if (minorsBehind(version, latest) > maxMinorsBehind) {\n faults.push(`${stamp.page}: the run ${newest.id} used ${name} ${version}, and npm had ${latest} at its start. The limit is ${maxMinorsBehind} minor version behind.`);\n }\n }\n }\n return { faults, notRun };\n}\n\n/** The help of the command `site-pages freshness`. */\nexport const FRESHNESS_HELP: string = `Usage: site-pages freshness --stamps <file> [options]\n\nExamine the data stamps of the measured pages of a site.\n\n --stamps <file> The file of data stamps, schema ${DATA_STAMP_SCHEMA}. (necessary)\n --now <time> The ISO time of the check. The default is the time of the call.\n --help Show this text.\n\nThe exit code is 0 when the stamps pass, 1 for a fault, and 2 for an incorrect command line.\n`;\n\n/** This function gives the largest gap of the schedule in a workflow file. It gives a text for a file that it cannot read. */\nfunction readSchedule(path: string): number | string {\n try {\n return scheduleGapDays(readFileSync(path, \"utf8\"));\n } catch (error) {\n return `the file cannot be read: ${error instanceof Error ? error.message : String(error)}`;\n }\n}\n\n/** This function is the command `site-pages freshness`. The `fetch` option is for a test. */\nexport async function runFreshnessCli(argv: readonly string[], io: CheckIo, fetcher?: typeof fetch): Promise<number> {\n let values: { stamps?: string | undefined; now?: string | undefined; help?: boolean | undefined };\n try {\n ({ values } = parseArgs({ args: [...argv], allowPositionals: false, options: { stamps: { type: \"string\" }, now: { type: \"string\" }, help: { type: \"boolean\" } } }));\n } catch (error) {\n io.stderr(`site-pages freshness: ${error instanceof Error ? error.message : String(error)}\\n\\n${FRESHNESS_HELP}`);\n return 2;\n }\n if (values.help === true) {\n io.stdout(FRESHNESS_HELP);\n return 0;\n }\n if (values.stamps === undefined) {\n io.stderr(`site-pages freshness: --stamps is necessary.\\n\\n${FRESHNESS_HELP}`);\n return 2;\n }\n const path = isAbsolute(values.stamps) ? values.stamps : join(io.cwd, values.stamps);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, \"utf8\"));\n } catch (error) {\n io.stderr(`site-pages freshness: the file ${values.stamps} cannot be read: ${error instanceof Error ? error.message : String(error)}\\n`);\n return 1;\n }\n const parsed = parseDataStamps(raw);\n if (!parsed.ok) {\n for (const fault of parsed.faults) io.stderr(`${fault}\\n`);\n return 1;\n }\n const engines = parsed.stamps.pages\n .filter((p) => p.study !== true)\n .flatMap((p) => [...p.runs, ...(p.inFlight === undefined ? [] : [p.inFlight])])\n .flatMap((r) => Object.keys(r.engines));\n const schedules: Record<string, number | string> = {};\n for (const page of parsed.stamps.pages) {\n if (page.limit !== undefined) schedules[page.limit.workflow] = readSchedule(join(io.cwd, page.limit.workflow));\n }\n const npm = await npmPublishTimes({ packages: [...new Set(engines)], ...(fetcher === undefined ? {} : { fetch: fetcher }) });\n const result = checkFreshness(parsed.stamps, { now: values.now ?? new Date().toISOString(), times: npm.times, schedules });\n for (const problem of [...npm.problems, ...result.notRun]) io.stdout(`Not run: ${problem}\\n`);\n for (const fault of result.faults) io.stderr(`${fault}\\n`);\n if (result.faults.length > 0) return 1;\n io.stdout(`The data stamps of ${parsed.stamps.pages.length} pages pass.\\n`);\n return 0;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"freshness.js","names":[],"sources":["../../src/data/versions.ts","../../src/data/npm.ts","../../src/data/git.ts","../../src/data/kpi.ts","../../src/render/html.ts","../../src/check/freshness.ts"],"sourcesContent":["/**\n * Versions: the SemVer parser, the sort, the kind of a version and the version of a git tag.\n */\n\nimport type { ReleaseKind } from \"./types.ts\";\n\n/** The parts of a SemVer 2.0.0 version. */\nexport interface ParsedVersion {\n major: number;\n minor: number;\n patch: number;\n prerelease: string[];\n}\n\nconst SEMVER = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?$/;\n\n/** This function gives the parts of a version, or null when the text is not a SemVer version. */\nexport function parseVersion(version: string): ParsedVersion | null {\n const match = SEMVER.exec(version);\n if (!match) return null;\n return {\n major: Number(match[1]),\n minor: Number(match[2]),\n patch: Number(match[3]),\n prerelease: match[4] ? match[4].split(\".\") : [],\n };\n}\n\n/**\n * This function compares two versions by the SemVer precedence. It gives a negative number when `a`\n * is older, a positive number when `a` is newer, and 0 for the same version. A text that is not a\n * version comes before each version.\n */\nexport function compareVersions(a: string, b: string): number {\n const x = parseVersion(a);\n const y = parseVersion(b);\n if (!x || !y) return x ? 1 : y ? -1 : a.localeCompare(b);\n const core = x.major - y.major || x.minor - y.minor || x.patch - y.patch;\n if (core !== 0) return core;\n // A prerelease comes before its release: 1.0.0-rc.1 < 1.0.0\n if (x.prerelease.length === 0 || y.prerelease.length === 0) return y.prerelease.length - x.prerelease.length;\n for (let index = 0; index < Math.max(x.prerelease.length, y.prerelease.length); index++) {\n const p = x.prerelease[index];\n const q = y.prerelease[index];\n if (p === undefined) return -1;\n if (q === undefined) return 1;\n if (p === q) continue;\n const pNumber = /^\\d+$/.test(p);\n const qNumber = /^\\d+$/.test(q);\n if (pNumber && qNumber) return Number(p) - Number(q);\n if (pNumber !== qNumber) return pNumber ? -1 : 1;\n return p < q ? -1 : 1;\n }\n return 0;\n}\n\n/**\n * This function gives the kind of a version. The oldest version of the list is \"first\". The caller\n * tells if the version is the oldest.\n */\nexport function kindOf(version: string, oldest: boolean): ReleaseKind {\n if (oldest) return \"first\";\n const parsed = parseVersion(version);\n if (!parsed) return \"patch\";\n if (parsed.major > 0 && parsed.minor === 0 && parsed.patch === 0) return \"major\";\n return parsed.patch === 0 ? \"minor\" : \"patch\";\n}\n\n/** The version of a git tag, and the package that the tag names (null for a tag like `v1.2.3`). */\nexport interface TagVersion {\n version: string;\n package: string | null;\n}\n\n/**\n * This function reads the version of a git tag. It knows `1.2.3`, `v1.2.3` and the tags of Changesets:\n * `name@1.2.3` and `@scope/name@1.2.3`. It gives null for another tag.\n */\nexport function versionOfTag(tag: string): TagVersion | null {\n const match = /^(?:(.+)@)?v?(\\d+\\.\\d+\\.\\d+(?:[-+][0-9A-Za-z.+-]*)?)$/.exec(tag.trim());\n if (!match || match[2] === undefined || !parseVersion(match[2])) return null;\n return { version: match[2], package: match[1] ?? null };\n}\n","/**\n * The npm source: the publication time of each version of some packages. The release data uses\n * these times when git and GitHub give no date for a version.\n */\n\nimport type { NpmPublishTimes, NpmVersionTime } from \"./types.ts\";\n\n/** The public npm registry. */\nexport const NPM_REGISTRY = \"https://registry.npmjs.org\";\n\n/** The options of `npmPublishTimes`. */\nexport interface NpmOptions {\n /** The npm names of the packages, or a scope (for example `@procedures`) for all the packages of the scope. */\n packages: readonly string[];\n /** The `fetch` function. The default is the global `fetch`. */\n fetch?: typeof fetch;\n registry?: string;\n /** The time limit of each request, in milliseconds. The default is 15000. */\n timeoutMs?: number;\n}\n\ntype Json = Record<string, unknown>;\nconst object = (value: unknown): Json => (value !== null && typeof value === \"object\" ? (value as Json) : {});\n\nfunction message(error: unknown): string {\n if (object(error)[\"name\"] === \"TimeoutError\") return \"npm did not answer in time\";\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * This function reads the publication time of each version of the packages from the npm registry.\n * A scope (`@name`) gives each package of the scope. It does not throw. Each failure gives a\n * message in `problems`.\n */\nexport async function npmPublishTimes(options: NpmOptions): Promise<NpmPublishTimes> {\n const { registry = NPM_REGISTRY, timeoutMs = 15_000 } = options;\n const fetcher = options.fetch ?? globalThis.fetch;\n const problems: string[] = [];\n const times: NpmVersionTime[] = [];\n if (typeof fetcher !== \"function\") return { times, problems: [\"this Node has no fetch\"] };\n const get = async (url: string): Promise<unknown> => {\n const response = await fetcher(url, { headers: { accept: \"application/json\" }, signal: AbortSignal.timeout(timeoutMs) });\n if (!response.ok) throw new Error(`HTTP ${response.status}`);\n return response.json();\n };\n\n const names = new Set<string>();\n for (const entry of options.packages.map((name) => name.trim()).filter(Boolean)) {\n if (!/^@[^/]+$/.test(entry)) {\n names.add(entry);\n continue;\n }\n try {\n const found = object(await get(`${registry}/-/v1/search?text=scope:${encodeURIComponent(entry.slice(1))}&size=250`));\n const objects = Array.isArray(found[\"objects\"]) ? found[\"objects\"] : [];\n const before = names.size;\n for (const item of objects) {\n const name = object(object(item)[\"package\"])[\"name\"];\n if (typeof name === \"string\" && name.startsWith(`${entry}/`)) names.add(name);\n }\n if (names.size === before) problems.push(`npm has no package in the scope ${entry}`);\n } catch (error) {\n problems.push(`npm did not give the packages of ${entry}: ${message(error)}`);\n }\n }\n\n // Four requests at a time\n const queue = [...names].sort();\n const worker = async (): Promise<void> => {\n for (let name = queue.shift(); name !== undefined; name = queue.shift()) {\n try {\n const packument = object(await get(`${registry}/${name.replaceAll(\"/\", \"%2f\")}`));\n const published = object(packument[\"versions\"]);\n for (const [version, date] of Object.entries(object(packument[\"time\"]))) {\n if (version === \"created\" || version === \"modified\" || typeof date !== \"string\") continue;\n if (!(version in published)) continue;\n times.push({ name, version, date });\n }\n } catch (error) {\n problems.push(`npm did not give the versions of ${name}: ${message(error)}`);\n }\n }\n };\n await Promise.all(Array.from({ length: 4 }, worker));\n times.sort((a, b) => a.name.localeCompare(b.name) || a.date.localeCompare(b.date));\n return { times, problems };\n}\n","/**\n * The git source: the tags with their dates, the commit of the build and the GitHub remote. Each\n * function gives an empty result when git or the repository is not available.\n */\n\nimport { execFileSync } from \"node:child_process\";\n\n/** A git tag and the ISO date of its creation. */\nexport interface TagDate {\n tag: string;\n date: string;\n}\n\n/** This function starts git in a folder and gives its output, or null when git fails. */\nexport function git(repoDir: string, ...args: string[]): string | null {\n try {\n return execFileSync(\"git\", args, { cwd: repoDir, encoding: \"utf8\", stdio: [\"ignore\", \"pipe\", \"ignore\"], windowsHide: true });\n } catch {\n return null;\n }\n}\n\n/** This function tells if the clone is shallow. A shallow clone has not all the tags and commits. */\nexport function isShallow(repoDir: string): boolean {\n return git(repoDir, \"rev-parse\", \"--is-shallow-repository\")?.trim() === \"true\";\n}\n\n/** This function gives each tag of the repository with its date. An annotated tag has its own date. */\nexport function gitTagDates(repoDir: string): TagDate[] {\n const output = git(repoDir, \"for-each-ref\", \"--format=%(refname:strip=2) %(creatordate:iso-strict)\", \"refs/tags\");\n if (!output) return [];\n const tags: TagDate[] = [];\n for (const line of output.split(/\\r?\\n/)) {\n const match = /^(\\S+) (\\S+)$/.exec(line.trim());\n if (match?.[1] && match[2]) tags.push({ tag: match[1], date: match[2] });\n }\n return tags;\n}\n\n/**\n * This function gives the date of the oldest commit that added a version heading to a changelog,\n * or null. The path of the changelog starts at `repoDir`.\n */\nexport function headingDate(repoDir: string, version: string, file: string): string | null {\n const output = git(repoDir, \"log\", \"--format=%cI\", `-S## ${version}`, \"--\", file);\n const dates = (output ?? \"\").trim().split(/\\r?\\n/).filter(Boolean);\n return dates[dates.length - 1] ?? null;\n}\n\n/** This function gives the full SHA of `HEAD`, or null. */\nexport function headCommit(repoDir: string): string | null {\n const sha = git(repoDir, \"rev-parse\", \"HEAD\")?.trim();\n return sha && /^[0-9a-f]{40}$/.test(sha) ? sha : null;\n}\n\n/** This function gives \"owner/name\" of the GitHub remote \"origin\", or null. */\nexport function originRepository(repoDir: string): string | null {\n const url = git(repoDir, \"remote\", \"get-url\", \"origin\")?.trim() ?? \"\";\n const match = /github\\.com[:/]([^/]+)\\/(.+?)(?:\\.git)?\\/?$/.exec(url);\n return match ? `${match[1]}/${match[2]}` : null;\n}\n","/**\n * The file `kpi.json` at the root of a site, format `kpi/1`. A reader outside the site takes the measures of the project\n * from this file. Thus a number on a progress page comes from a record and not from a person.\n *\n * The field `at` is the time of the data and not the time of the build. Thus the writer has no default for it.\n * A measure can have its own `at` when its data is from another time than the rest of the file.\n */\n\nimport { mkdirSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { KpiEngine, KpiFile, KpiMeasure } from \"./types.ts\";\n\n/** The name of the format. A new format gets a new name, so that an old reader refuses it. */\nexport const KPI_FORMAT = \"kpi/1\";\n\n/** The name of the file at the root of the built site. */\nexport const KPI_FILE = \"kpi.json\";\n\n/** The data of `kpi.json`, without the name of the format. */\nexport type KpiInput = Omit<KpiFile, \"format\">;\n\n/** The form of a project and a measure. A double hyphen separates fields in the file name of a reading. */\nconst SLUG = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;\n\n/** The form of a time in UTC, with or without seconds. */\nconst UTC_TIME = /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d+)?)?Z$/;\n\n/** The form of a full commit. */\nconst COMMIT = /^[0-9a-f]{40}$/;\n\n/** The clock difference between two computers that the check accepts, in milliseconds. */\nconst CLOCK_MARGIN = 5 * 60 * 1000;\n\n/** An error in the data of `kpi.json`. The field `problems` has one line for each fault. */\nexport class KpiError extends Error {\n readonly problems: readonly string[];\n\n constructor(problems: readonly string[]) {\n super(`${KPI_FILE} is not correct: ${problems.join(\" \")}`);\n this.name = \"KpiError\";\n this.problems = problems;\n }\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> => typeof value === \"object\" && value !== null && !Array.isArray(value);\n\nconst isText = (value: unknown): value is string => typeof value === \"string\" && value.trim() !== \"\";\n\n/** This function gives the fault of a time of the data, or an empty list. The name tells which field it is. */\nfunction timeProblems(at: unknown, name: string, now: number): string[] {\n if (typeof at !== \"string\" || !UTC_TIME.test(at) || Number.isNaN(Date.parse(at))) return [`${name} is not a time in UTC.`];\n return Date.parse(at) > now + CLOCK_MARGIN ? [`The time of the data ${at} is after the time of the check.`] : [];\n}\n\n/** This function gives the faults of one measure. */\nfunction measureProblems(value: unknown, index: number, seen: Set<string>, now: number): string[] {\n if (!isRecord(value)) return [`Measure ${index} is not an object.`];\n const { id, value: amount, unit, at } = value;\n const problems: string[] = [];\n if (typeof id !== \"string\" || !SLUG.test(id)) problems.push(`Measure ${index} has no id of lowercase words with single hyphens.`);\n else if (seen.has(id)) problems.push(`The id ${id} occurs two times.`);\n else seen.add(id);\n if (typeof amount !== \"number\" || !Number.isFinite(amount)) problems.push(`Measure ${index} has no finite number as its value.`);\n if (unit !== undefined && !isText(unit)) problems.push(`Measure ${index} has a unit that is not a text.`);\n if (at !== undefined) problems.push(...timeProblems(at, `The field at of measure ${index}`, now));\n return problems;\n}\n\n/** This function gives the faults of the list of engines. */\nfunction engineProblems(value: unknown): string[] {\n if (value === undefined) return [];\n if (!Array.isArray(value)) return [\"The field engines is not a list.\"];\n return value.flatMap((engine: unknown, index) => (isRecord(engine) && isText(engine[\"name\"]) && isText(engine[\"version\"]) ? [] : [`Engine ${index} has no name and version.`]));\n}\n\n/**\n * This function gives the faults of a parsed `kpi.json`, or an empty list.\n *\n * @param value - The parsed file.\n * @param now - The time of the check, in milliseconds. A time of the data after this time is a fault.\n */\nexport function kpiProblems(value: unknown, now: number = Date.now()): string[] {\n if (!isRecord(value)) return [\"The file is not an object.\"];\n const problems: string[] = [];\n if (value[\"format\"] !== KPI_FORMAT) problems.push(`The format is not ${KPI_FORMAT}.`);\n const { project, at, commit, measures } = value;\n if (typeof project !== \"string\" || !SLUG.test(project)) problems.push(\"The project is not lowercase words with single hyphens.\");\n problems.push(...timeProblems(at, \"The field at\", now));\n if (typeof commit !== \"string\" || !COMMIT.test(commit)) problems.push(\"The commit is not a full commit.\");\n if (!Array.isArray(measures) || measures.length === 0) problems.push(\"The file has no measures.\");\n else {\n const seen = new Set<string>();\n problems.push(...measures.flatMap((measure: unknown, index) => measureProblems(measure, index, seen, now)));\n }\n problems.push(...engineProblems(value[\"engines\"]));\n return problems;\n}\n\n/** This function gives a copy of a measure with only its known fields. */\nfunction cleanMeasure({ id, value, unit, at }: KpiMeasure): KpiMeasure {\n return { id, value, ...(unit === undefined ? {} : { unit }), ...(at === undefined ? {} : { at }) };\n}\n\n/** This function gives a copy of an engine with only its known fields. */\nfunction cleanEngine({ name, version }: KpiEngine): KpiEngine {\n return { name, version };\n}\n\n/**\n * This function gives the checked content of `kpi.json`. The file has only its known fields, in a fixed order.\n *\n * @throws KpiError when the data is not correct\n */\nexport function kpiFile(input: KpiInput, now?: number): KpiFile {\n const problems = kpiProblems({ format: KPI_FORMAT, ...input }, now);\n if (problems.length > 0) throw new KpiError(problems);\n const { project, at, commit, measures, engines } = input;\n const file: KpiFile = { format: KPI_FORMAT, project, at, commit, measures: measures.map(cleanMeasure) };\n return engines === undefined ? file : { ...file, engines: engines.map(cleanEngine) };\n}\n\n/** This function gives the text of `kpi.json`. */\nexport function kpiText(file: KpiFile): string {\n return `${JSON.stringify(file, null, 2)}\\n`;\n}\n\n/**\n * This function reads the text of a `kpi.json`.\n *\n * @throws KpiError when the text is not correct\n */\nexport function readKpi(text: string, now?: number): KpiFile {\n let value: unknown;\n try {\n value = JSON.parse(text);\n } catch (error) {\n throw new KpiError([`The file is not JSON: ${error instanceof Error ? error.message : String(error)}`]);\n }\n const problems = kpiProblems(value, now);\n if (problems.length > 0) throw new KpiError(problems);\n const { project, at, commit, measures, engines } = value as KpiFile;\n return kpiFile(engines === undefined ? { project, at, commit, measures } : { project, at, commit, measures, engines }, now);\n}\n\n/**\n * This function writes `kpi.json` into the built output folder of a site, and gives the path of the file.\n *\n * @throws KpiError when the data is not correct\n */\nexport function writeKpi(out: string, input: KpiInput, now?: number): string {\n const text = kpiText(kpiFile(input, now));\n mkdirSync(out, { recursive: true });\n const file = join(out, KPI_FILE);\n writeFileSync(file, text);\n return file;\n}\n","/**\n * The HTML helpers of the pages: the escape functions and a small inline Markdown renderer.\n */\n\nconst ESCAPES: Record<string, string> = { \"&\": \"&\", \"<\": \"<\", \">\": \">\", '\"': \""\", \"'\": \"'\" };\n\n/** This function escapes a text for HTML content and for an attribute value in double quotes. */\nexport function escapeHtml(text: string): string {\n return String(text).replace(/[&<>\"']/g, (char) => ESCAPES[char] ?? char);\n}\n\n/**\n * This function removes the control characters and the spaces (U+0000 to U+0020) at the two ends\n * of a text. A loop does it, because the regular expression `[\\u0000- ]+$` backtracks. For a long\n * run of these characters, its time grows with the square of the length.\n */\nfunction trimControl(text: string): string {\n let start = 0;\n let end = text.length;\n while (start < end && text.charCodeAt(start) <= 0x20) start++;\n while (end > start && text.charCodeAt(end - 1) <= 0x20) end--;\n return text.slice(start, end);\n}\n\n/**\n * This function gives a URL that a link can hold, or null. It accepts `http:`, `https:` and\n * `mailto:` URLs, and relative URLs. It refuses each other scheme, for example `javascript:`.\n *\n * The URL parser of a browser removes each tab and line break, and the control characters and\n * spaces at the two ends. This function removes them before the scheme check, as the browser does.\n * Thus a control character before `javascript:` does not hide the scheme.\n */\nexport function safeUrl(url: string): string | null {\n const trimmed = trimControl(url.trim().replace(/[\\t\\n\\r]/g, \"\"));\n if (/^(?:https?:|mailto:)/i.test(trimmed)) return trimmed;\n // A browser reads \"\\\" as \"/\" in a URL of the page, so \"\\\\host\" and \"/\\host\" go to a different host, as \"//host\" does\n if (/^[a-z][a-z0-9+.-]*:/i.test(trimmed) || /^[/\\\\]{2}/.test(trimmed)) return null;\n return trimmed;\n}\n\n/** This function gives an `<a>` element, or the escaped text when the URL is not safe. */\nexport function link(url: string, html: string, attributes = \"\"): string {\n const href = safeUrl(url);\n return href === null ? html : `<a href=\"${escapeHtml(href)}\"${attributes ? ` ${attributes}` : \"\"}>${html}</a>`;\n}\n\n/** The emphasis of a text without code spans or links. The text is already escaped. */\nfunction emphasis(escaped: string): string {\n return escaped\n .replace(/\\*\\*([^*]+?)\\*\\*/g, \"<strong>$1</strong>\")\n .replace(/(^|[^\\w*])\\*([^*\\s][^*]*?)\\*(?![\\w*])/g, \"$1<em>$2</em>\")\n .replace(/(^|[^\\w])_([^_\\s][^_]*?)_(?![\\w])/g, \"$1<em>$2</em>\");\n}\n\nconst INLINE = \"`([^`]+)`|\\\\[((?:[^\\\\]`]|`[^`]*`)+)\\\\]\\\\(([^)\\\\s]+)\\\\)\";\n\n/**\n * This function renders inline Markdown as HTML: code spans, links, strong text and emphasis. It\n * escapes all other text, so the result is safe.\n */\nexport function inlineMarkdown(markdown: string): string {\n const text = String(markdown ?? \"\");\n // A new expression for each call: the text of a link is rendered with a recursive call\n const pattern = new RegExp(INLINE, \"g\");\n let html = \"\";\n let last = 0;\n for (let match = pattern.exec(text); match; match = pattern.exec(text)) {\n html += emphasis(escapeHtml(text.slice(last, match.index)));\n if (match[1] !== undefined) html += `<code>${escapeHtml(match[1])}</code>`;\n else html += link(match[3] ?? \"\", inlineMarkdown(match[2] ?? \"\"));\n last = match.index + match[0].length;\n }\n return html + emphasis(escapeHtml(text.slice(last)));\n}\n\n/** This function gives \"1 item\" or \"2 items\". */\nexport function plural(count: number, word: string, many = `${word}s`): string {\n return `${count} ${count === 1 ? word : many}`;\n}\n\n/** This function gives \"a\", \"a and b\" or \"a, b and c\". */\nexport function listText(parts: readonly string[]): string {\n if (parts.length <= 1) return parts.join(\"\");\n return `${parts.slice(0, -1).join(\", \")} and ${parts[parts.length - 1]}`;\n}\n","/**\n * The freshness gate of a measured page. A site keeps a file of data stamps.\n * Each stamp names the page, its runs, their dates and their engine versions.\n * The gate fails on a page with no versions or no run date, and on old data with no newer run in flight.\n * The gate also fails on a run that started behind the engines on npm.\n * A fixed study has no age limit. A page with a longer limit names the reason and the scheduled workflow that meets the limit.\n * This file imports only Node.js and the folder `data`, so `reusable-pages.yml` starts it with no npm release of the package.\n */\n\nimport { readFileSync } from \"node:fs\";\nimport { isAbsolute, join } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport { npmPublishTimes } from \"../data/npm.ts\";\nimport type { NpmVersionTime } from \"../data/types.ts\";\nimport { compareVersions, parseVersion } from \"../data/versions.ts\";\nimport type { CheckIo } from \"./check.ts\";\n\n/** The schema of a file of data stamps. */\nexport const DATA_STAMP_SCHEMA = \"data-stamp/1\";\n\n/** The largest age of the data of a page, in days, when no newer run is in flight. */\nexport const MAX_DATA_AGE_DAYS = 3;\n\n/** The most minor versions that an engine of a run can be behind npm at the start of the run. */\nexport const MAX_MINORS_BEHIND = 1;\n\n/** The longest limit of a page, in days, with no ruling for that site. */\nexport const MAX_LIMIT_DAYS_WITHOUT_RULING = 14;\n\nconst DAY_MS = 86_400_000;\n\n/** One run that gives the data of a page. */\nexport interface DataRun {\n readonly id: string;\n readonly url: string;\n /** The ISO time of the start of the run. */\n readonly date: string;\n /** The version of each engine of the run, by its npm name. */\n readonly engines: Readonly<Record<string, string>>;\n}\n\n/** The age limit of one page, in place of `MAX_DATA_AGE_DAYS`. */\nexport interface DataLimit {\n /** The largest age of the data, in days. */\n readonly days: number;\n /** The reason for the limit, as one sentence. The page shows it. */\n readonly reason: string;\n /** The path of the workflow from the root of the repository. Its schedule must meet the limit. */\n readonly workflow: string;\n /** The link to the public ruling. A limit over `MAX_LIMIT_DAYS_WITHOUT_RULING` needs it. */\n readonly ruling?: string;\n}\n\n/** The stamp of one measured page. */\nexport interface PageStamp {\n readonly page: string;\n /** Each run that gives data to the page. */\n readonly runs: readonly DataRun[];\n /** The run on newer engines that is in progress. */\n readonly inFlight?: DataRun;\n /** The page shows a fixed study of the versions of its runs, so its data has no age limit. It makes no claim about a newer release. */\n readonly study?: true;\n /** The age limit of this page, in place of the default. */\n readonly limit?: DataLimit;\n}\n\n/** The content of a file of data stamps. */\nexport interface DataStamps {\n readonly schema: typeof DATA_STAMP_SCHEMA;\n readonly pages: readonly PageStamp[];\n}\n\n/** The result of `parseDataStamps`. */\nexport type DataStampsParse = { readonly ok: true; readonly stamps: DataStamps } | { readonly ok: false; readonly faults: readonly string[] };\n\n/** The options of `checkFreshness`. */\nexport interface FreshnessOptions {\n /** The ISO time of the check. */\n readonly now: string;\n /** The publication times of the engines on npm. */\n readonly times: readonly NpmVersionTime[];\n /** The limit of the age. The default is `MAX_DATA_AGE_DAYS`. */\n readonly maxAgeDays?: number;\n /** The limit of the minor versions. The default is `MAX_MINORS_BEHIND`. */\n readonly maxMinorsBehind?: number;\n /** The schedule of each workflow of a limit. A number is the largest gap between its starts in days. A text tells why the gate cannot read it. */\n readonly schedules?: Readonly<Record<string, number | string>>;\n}\n\n/** The result of `checkFreshness`. */\nexport interface FreshnessCheck {\n /** Each break of a rule. One fault fails the gate. */\n readonly faults: readonly string[];\n /** Each rule that the gate could not run, with the reason. */\n readonly notRun: readonly string[];\n}\n\nconst record = (value: unknown): Record<string, unknown> | null => (value !== null && typeof value === \"object\" && !Array.isArray(value) ? (value as Record<string, unknown>) : null);\n\n/** This function gives the faults of one run of a stamp. */\nfunction runFaults(raw: unknown, at: string): string[] {\n const run = record(raw);\n if (run === null) return [`${at}: a run is not an object.`];\n const faults: string[] = [];\n if (typeof run[\"id\"] !== \"string\" || run[\"id\"] === \"\") faults.push(`${at}: a run has no id.`);\n const label = `${at}, run ${String(run[\"id\"])}`;\n if (typeof run[\"url\"] !== \"string\" || !run[\"url\"].startsWith(\"https://\")) faults.push(`${label}: the run has no https link.`);\n if (typeof run[\"date\"] !== \"string\" || !Number.isFinite(Date.parse(run[\"date\"]))) faults.push(`${label}: the run has no date.`);\n const engines = record(run[\"engines\"]);\n if (engines === null || Object.keys(engines).length === 0) return [...faults, `${label}: the run names no engine versions.`];\n for (const [name, version] of Object.entries(engines)) {\n if (typeof version !== \"string\" || parseVersion(version) === null) faults.push(`${label}: the version of ${name} is not a version.`);\n }\n return faults;\n}\n\n/** This function gives the faults of the age limit of one page. */\nfunction limitFaults(raw: unknown, at: string): string[] {\n const limit = record(raw);\n if (limit === null) return [`${at}: the limit is not an object.`];\n const faults: string[] = [];\n const days = limit[\"days\"];\n if (typeof days !== \"number\" || !Number.isFinite(days) || days <= 0) faults.push(`${at}: the limit has no count of days.`);\n if (typeof limit[\"reason\"] !== \"string\" || limit[\"reason\"].trim() === \"\") faults.push(`${at}: the limit has no reason.`);\n if (typeof limit[\"workflow\"] !== \"string\" || limit[\"workflow\"] === \"\") faults.push(`${at}: the limit names no workflow.`);\n const ruling = limit[\"ruling\"];\n if (ruling !== undefined && (typeof ruling !== \"string\" || !ruling.startsWith(\"https://\"))) faults.push(`${at}: the ruling of the limit has no https link.`);\n if (typeof days === \"number\" && days > MAX_LIMIT_DAYS_WITHOUT_RULING && ruling === undefined) {\n faults.push(`${at}: a limit over ${MAX_LIMIT_DAYS_WITHOUT_RULING} days needs a ruling for this site.`);\n }\n return faults;\n}\n\n/** This function gives the faults of the fields of a page that change the age rule. */\nfunction ageRuleFaults(page: Record<string, unknown>, at: string): string[] {\n const faults: string[] = [];\n const study = page[\"study\"];\n if (study !== undefined && study !== true) faults.push(`${at}: the field study is not true.`);\n if (study === true && page[\"limit\"] !== undefined) faults.push(`${at}: a fixed study has no limit.`);\n if (study === true && page[\"inFlight\"] !== undefined) faults.push(`${at}: a fixed study has no run in flight.`);\n if (page[\"limit\"] !== undefined) faults.push(...limitFaults(page[\"limit\"], at));\n return faults;\n}\n\n/**\n * This function reads the content of a file of data stamps. It gives each fault of the content, so a page with no versions\n * or no run date fails here.\n */\nexport function parseDataStamps(raw: unknown): DataStampsParse {\n const file = record(raw);\n if (file === null) return { ok: false, faults: [\"The file is not an object.\"] };\n if (file[\"schema\"] !== DATA_STAMP_SCHEMA) return { ok: false, faults: [`The schema is not ${DATA_STAMP_SCHEMA}.`] };\n const pages = file[\"pages\"];\n if (!Array.isArray(pages) || pages.length === 0) return { ok: false, faults: [\"The file has no pages.\"] };\n const faults: string[] = [];\n for (const item of pages) {\n const page = record(item);\n if (page === null || typeof page[\"page\"] !== \"string\" || page[\"page\"] === \"\") {\n faults.push(\"A stamp has no page.\");\n continue;\n }\n const at = page[\"page\"];\n const runs = page[\"runs\"];\n if (!Array.isArray(runs) || runs.length === 0) faults.push(`${at}: the page names no run.`);\n else for (const run of runs) faults.push(...runFaults(run, at));\n if (page[\"inFlight\"] !== undefined) faults.push(...runFaults(page[\"inFlight\"], `${at}, in flight`));\n faults.push(...ageRuleFaults(page, at));\n }\n return faults.length > 0 ? { ok: false, faults } : { ok: true, stamps: raw as DataStamps };\n}\n\n/** This function gives the count of minor versions from `used` to `latest`. A newer major version counts as no limit. */\nexport function minorsBehind(used: string, latest: string): number {\n const a = parseVersion(used);\n const b = parseVersion(latest);\n if (a === null || b === null) return Number.POSITIVE_INFINITY;\n if (a.major !== b.major) return b.major > a.major ? Number.POSITIVE_INFINITY : 0;\n return Math.max(0, b.minor - a.minor);\n}\n\n/** This function gives the newest stable version of a package on npm at a time, or undefined when npm has none. */\nexport function latestAt(times: readonly NpmVersionTime[], name: string, date: string): string | undefined {\n const limit = Date.parse(date);\n return times\n .filter((t) => t.name === name && Date.parse(t.date) <= limit && parseVersion(t.version)?.prerelease.length === 0)\n .map((t) => t.version)\n .sort(compareVersions)\n .at(-1);\n}\n\nconst ageInDays = (date: string, now: number): number => (now - Date.parse(date)) / DAY_MS;\n\n/** This function gives the values of one field of a cron line, or undefined for a form that it cannot read. */\nfunction cronValues(field: string, low: number, high: number): Set<number> | undefined {\n const values = new Set<number>();\n for (const part of field.split(\",\")) {\n const match = /^(\\*|\\d+(?:-\\d+)?)(?:\\/(\\d+))?$/.exec(part);\n if (match === null) return undefined;\n const [, range = \"\", step = \"1\"] = match;\n const [from = low, to = from] = range === \"*\" ? [low, high] : range.split(\"-\").map(Number);\n const by = Number(step);\n if (by <= 0 || from < low || to > high || from > to) return undefined;\n for (let value = from; value <= to; value += by) values.add(value);\n }\n return values;\n}\n\n/** This function gives the start of each day of a cron line, in a span of two years. It gives undefined for a line that it cannot read. */\nfunction cronDays(line: string, from: number, days: number): number[] | undefined {\n const fields = line.trim().split(/\\s+/);\n if (fields.length !== 5) return undefined;\n const [minute = \"\", hour = \"\", dayOfMonth = \"\", month = \"\", dayOfWeek = \"\"] = fields;\n const minutes = cronValues(minute, 0, 59);\n const hours = cronValues(hour, 0, 23);\n const monthDays = cronValues(dayOfMonth, 1, 31);\n const months = cronValues(month, 1, 12);\n const weekDays = cronValues(dayOfWeek, 0, 6);\n if (minutes === undefined || hours === undefined || monthDays === undefined || months === undefined || weekDays === undefined) return undefined;\n const firstTime = (Math.min(...hours) * 60 + Math.min(...minutes)) * 60_000;\n const starts: number[] = [];\n for (let day = 0; day < days; day += 1) {\n const time = from + day * DAY_MS;\n const date = new Date(time);\n if (!months.has(date.getUTCMonth() + 1)) continue;\n const onMonthDay = monthDays.has(date.getUTCDate());\n const onWeekDay = weekDays.has(date.getUTCDay());\n // A cron line that sets both day fields starts on a day that matches one of them.\n const both = dayOfMonth !== \"*\" && dayOfWeek !== \"*\";\n if (both ? onMonthDay || onWeekDay : onMonthDay && onWeekDay) starts.push(time + firstTime);\n }\n return starts;\n}\n\n/** One schedule of a workflow. */\nexport interface CronLine {\n /** The number of the line in the file, from 1. */\n readonly line: number;\n /** The cron text, with no quotes and no comment. */\n readonly cron: string;\n}\n\n/**\n * This function gives each line `cron:` of a workflow. It is the one reader of these lines: the freshness gate and the rule `runner-budget` of conventions use it.\n * It skips a comment line. It reads a quoted key, a list item, a quoted value and a comment at the end of the line.\n */\nexport function cronLines(workflow: string): CronLine[] {\n return workflow.split(/\\r?\\n/).flatMap((raw, index) => {\n const text = raw.trim().replace(/^- */, \"\");\n const key = [\"cron:\", '\"cron\":', \"'cron':\"].find((form) => text.startsWith(form));\n if (key === undefined) return [];\n // YAML starts a comment at a \"#\" after a space or a tab.\n const rest = text.slice(key.length);\n const comment = rest.search(/\\s#/);\n const value = (comment >= 0 ? rest.slice(0, comment) : rest).trim();\n const quote = value.charAt(0);\n const quoted = value.length >= 2 && (quote === '\"' || quote === \"'\") && value.endsWith(quote);\n return [{ line: index + 1, cron: quoted ? value.slice(1, -1).trim() : value }];\n });\n}\n\n/**\n * This function gives the largest gap between the scheduled starts of a workflow, in days. The gap counts from the first start of a day.\n * It gives a text in place of the gap for a workflow with no schedule, and for a line that it cannot read. The text names the line, and the gate fails on it.\n */\nexport function scheduleGapDays(workflow: string): number | string {\n const lines = cronLines(workflow).map((item) => item.cron);\n if (lines.length === 0) return \"the workflow has no line `cron:`\";\n const from = Date.UTC(2027, 0, 1);\n const span = 731;\n const starts: number[] = [];\n for (const line of lines) {\n const days = cronDays(line, from, span);\n if (days === undefined) return `the gate cannot read the line \\`cron: ${line}\\``;\n starts.push(...days);\n }\n if (starts.length < 2) return `the lines \\`cron: ${lines.join(\"`, `cron: \")}\\` give fewer than two starts in two years`;\n starts.sort((a, b) => a - b);\n let largest = 0;\n for (let index = 1; index < starts.length; index += 1) largest = Math.max(largest, ((starts[index] ?? 0) - (starts[index - 1] ?? 0)) / DAY_MS);\n return largest;\n}\n\n/** This function tells if a run uses a newer version of an engine than another run. */\nfunction hasNewerEngine(run: DataRun, than: DataRun): boolean {\n return Object.entries(run.engines).some(([name, version]) => {\n const old = than.engines[name];\n return old !== undefined && compareVersions(version, old) > 0;\n });\n}\n\n/**\n * This function applies the rules of the gate to the stamps.\n *\n * - The data of each page is at most `maxAgeDays` old, or a run on newer engines is in flight.\n * - The engines of the newest run are at most `maxMinorsBehind` behind npm at the start of that run.\n * - A run in flight has the same age limit, so an old stamp does not hold the gate open.\n * - A page with its own limit uses that limit, and the schedule of its workflow meets the limit.\n * - A fixed study has no age limit and no limit of the engines, because it tells about the versions that it names.\n */\nexport function checkFreshness(stamps: DataStamps, options: FreshnessOptions): FreshnessCheck {\n const { times, maxAgeDays: defaultAge = MAX_DATA_AGE_DAYS, maxMinorsBehind = MAX_MINORS_BEHIND, schedules = {} } = options;\n const now = Date.parse(options.now);\n const faults: string[] = [];\n const notRun: string[] = [];\n for (const stamp of stamps.pages) {\n for (const run of [...stamp.runs, ...(stamp.inFlight === undefined ? [] : [stamp.inFlight])]) {\n if (ageInDays(run.date, now) < 0) faults.push(`${stamp.page}: the run ${run.id} has a date after the check.`);\n }\n if (stamp.study === true) continue;\n const maxAgeDays = stamp.limit?.days ?? defaultAge;\n if (stamp.limit !== undefined) {\n const gap = schedules[stamp.limit.workflow];\n if (gap === undefined || typeof gap === \"string\") faults.push(`${stamp.page}: the limit of ${maxAgeDays} days has no schedule that the gate can read in ${stamp.limit.workflow}: ${gap ?? \"the check has no read of this workflow\"}.`);\n else if (gap > maxAgeDays) faults.push(`${stamp.page}: the schedule of ${stamp.limit.workflow} has a gap of ${gap.toFixed(1)} days, over the limit of ${maxAgeDays}.`);\n }\n const flight = stamp.inFlight;\n const flying = flight !== undefined && ageInDays(flight.date, now) <= maxAgeDays;\n if (flight !== undefined && !flying) faults.push(`${stamp.page}: the run ${flight.id} is in flight for more than ${maxAgeDays} days.`);\n for (const run of stamp.runs) {\n const age = ageInDays(run.date, now);\n if (age > maxAgeDays && !(flying && hasNewerEngine(flight, run))) {\n faults.push(`${stamp.page}: the run ${run.id} is ${age.toFixed(1)} days old, over the limit of ${maxAgeDays}, and no run on newer engines is in flight.`);\n }\n }\n const newest = flight ?? [...stamp.runs].sort((a, b) => Date.parse(a.date) - Date.parse(b.date)).at(-1);\n if (newest === undefined) continue;\n for (const [name, version] of Object.entries(newest.engines)) {\n const latest = latestAt(times, name, newest.date);\n if (latest === undefined) {\n notRun.push(`${stamp.page}: npm gives no version of ${name} at the start of the run ${newest.id}.`);\n } else if (minorsBehind(version, latest) > maxMinorsBehind) {\n faults.push(`${stamp.page}: the run ${newest.id} used ${name} ${version}, and npm had ${latest} at its start. The limit is ${maxMinorsBehind} minor version behind.`);\n }\n }\n }\n return { faults, notRun };\n}\n\n/** The help of the command `site-pages freshness`. */\nexport const FRESHNESS_HELP: string = `Usage: site-pages freshness --stamps <file> [options]\n\nExamine the data stamps of the measured pages of a site.\n\n --stamps <file> The file of data stamps, schema ${DATA_STAMP_SCHEMA}. (necessary)\n --now <time> The ISO time of the check. The default is the time of the call.\n --help Show this text.\n\nThe exit code is 0 when the stamps pass, 1 for a fault, and 2 for an incorrect command line.\n`;\n\n/** This function gives the largest gap of the schedule in a workflow file. It gives a text for a file that it cannot read. */\nfunction readSchedule(path: string): number | string {\n try {\n return scheduleGapDays(readFileSync(path, \"utf8\"));\n } catch (error) {\n return `the file cannot be read: ${error instanceof Error ? error.message : String(error)}`;\n }\n}\n\n/** This function is the command `site-pages freshness`. The `fetch` option is for a test. */\nexport async function runFreshnessCli(argv: readonly string[], io: CheckIo, fetcher?: typeof fetch): Promise<number> {\n let values: { stamps?: string | undefined; now?: string | undefined; help?: boolean | undefined };\n try {\n ({ values } = parseArgs({ args: [...argv], allowPositionals: false, options: { stamps: { type: \"string\" }, now: { type: \"string\" }, help: { type: \"boolean\" } } }));\n } catch (error) {\n io.stderr(`site-pages freshness: ${error instanceof Error ? error.message : String(error)}\\n\\n${FRESHNESS_HELP}`);\n return 2;\n }\n if (values.help === true) {\n io.stdout(FRESHNESS_HELP);\n return 0;\n }\n if (values.stamps === undefined) {\n io.stderr(`site-pages freshness: --stamps is necessary.\\n\\n${FRESHNESS_HELP}`);\n return 2;\n }\n const path = isAbsolute(values.stamps) ? values.stamps : join(io.cwd, values.stamps);\n let raw: unknown;\n try {\n raw = JSON.parse(readFileSync(path, \"utf8\"));\n } catch (error) {\n io.stderr(`site-pages freshness: the file ${values.stamps} cannot be read: ${error instanceof Error ? error.message : String(error)}\\n`);\n return 1;\n }\n const parsed = parseDataStamps(raw);\n if (!parsed.ok) {\n for (const fault of parsed.faults) io.stderr(`${fault}\\n`);\n return 1;\n }\n const engines = parsed.stamps.pages\n .filter((p) => p.study !== true)\n .flatMap((p) => [...p.runs, ...(p.inFlight === undefined ? [] : [p.inFlight])])\n .flatMap((r) => Object.keys(r.engines));\n const schedules: Record<string, number | string> = {};\n for (const page of parsed.stamps.pages) {\n if (page.limit !== undefined) schedules[page.limit.workflow] = readSchedule(join(io.cwd, page.limit.workflow));\n }\n const npm = await npmPublishTimes({ packages: [...new Set(engines)], ...(fetcher === undefined ? {} : { fetch: fetcher }) });\n const result = checkFreshness(parsed.stamps, { now: values.now ?? new Date().toISOString(), times: npm.times, schedules });\n for (const problem of [...npm.problems, ...result.notRun]) io.stdout(`Not run: ${problem}\\n`);\n for (const fault of result.faults) io.stderr(`${fault}\\n`);\n if (result.faults.length > 0) return 1;\n io.stdout(`The data stamps of ${parsed.stamps.pages.length} pages pass.\\n`);\n return 0;\n}\n"],"mappings":"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"}
|
package/build/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { u as runFreshnessCli } from "./chunks/freshness.js";
|
|
3
3
|
import { a as runCli, o as TYPESCRIPT_PROBE, s as probeScript } from "./chunks/build.js";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { appendFileSync, createReadStream, existsSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
@@ -181,6 +181,8 @@ export declare function nextStepsCap(steps: number, elapsedMs: number, budgetMs:
|
|
|
181
181
|
/**
|
|
182
182
|
* This function gives the data of a view. It does not throw. A request that the record refuses gives the text in
|
|
183
183
|
* `problem`, and no panels. A measure with no model gives only the measured points, and a table model gives cells.
|
|
184
|
+
* A smooth model that is no better than a plain mean also gives only the measured points. A drawn fit claims knowledge that such a model does not have.
|
|
185
|
+
* A table model keeps its cells at any error, because each cell is the mean of measured points.
|
|
184
186
|
*/
|
|
185
187
|
export declare function viewOf(record: ResponseRecord, state: ExplorerState, options?: ViewOptions): ExplorerView;
|
|
186
188
|
/** This function gives the numbers of a panel: each place of a curve, or the measured points of a surface. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/explorer/model.ts","../../src/explorer/view.ts"],"mappings":";;qBAkCa;;qBAEA;;;;;;qBAMA;;qBAEA;;qBAEA;;UAWI;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA,MAAM,SAAS,eAAe;;;KAI7B;;UAGK;WACN;WACA;WACA;;WAEA;;;UAIM;WACN,OAAO;WACP;WACA;WACA;;;UAIM;WACN;WACA;;WAEA;;WAEA;;WAEA;WACA,kBAAkB;WAClB,OAAO;;;UAID;WACN;WACA;WACA;WACA;;WAEA;;WAEA,iBAAiB;;;UAIlB;;WAEC;;WAEA,OAAO;;;UAID,mBAAmB;WACzB;WACA,OAAO;;;UAID,qBAAqB;WAC3B;WACA;WACA,SAAS;;;UAIH;WACN;;WAEA,aAAa;WACb;;;UAIM,oBAAoB;WAC1B;WACA,iBAAiB;;;KAIhB,gBAAgB,aAAa,eAAe;;UAGvC;WACN,SAAS;WACT,GAAG;WACH,GAAG;WACH,iBAAiB;;WAEjB;;WAEA,OAAO;;WAEP;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;;UAIM;;WAEN;;WAEA;;WAEA;;;UAIM;WACN;WACA;;;;;;wBAcK,WAAW,iBAAiB;;;;;;wBA0K5B,OAAO,QAAQ,gBAAgB,SAAQ,QAAQ,iBAAsB;;wBAqBrE,YAAY,QAAQ,gBAAgB,OAAO,eAAe,MAAM,oBAAoB;;wBAQpF,aAAa,QAAQ,gBAAgB,OAAO,yBAAyB;;wBAQrE,aAAa,QAAQ,gBAAgB,OAAO,yBAAyB;;wBAwBrE,WAAW,QAAQ,gBAAgB,OAAO,eAAe,kBAAkB;;wBAK3E,QAAQ,QAAQ,gBAAgB,OAAO,eAAe,MAAM,UAAU,oBAAoB;;wBAO1F,SAAS,QAAQ,gBAAgB,OAAO,eAAe,oBAAoB;;wBAM3E,QAAQ,QAAQ,gBAAgB,OAAO,eAAe,YAAY,OAAO,gBAAgB;;;;;;;;;;;wBAiBzF,UAAU,gBAAgB,gBAAgB,oBAAoB,gBAAgB;;wBAO9E,aAAa,eAAe,mBAAmB
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/explorer/model.ts","../../src/explorer/view.ts"],"mappings":";;qBAkCa;;qBAEA;;;;;;qBAMA;;qBAEA;;qBAEA;;UAWI;;WAEN;;WAEA;;WAEA;;WAEA;;WAEA,MAAM,SAAS,eAAe;;;KAI7B;;UAGK;WACN;WACA;WACA;;WAEA;;;UAIM;WACN,OAAO;WACP;WACA;WACA;;;UAIM;WACN;WACA;;WAEA;;WAEA;;WAEA;WACA,kBAAkB;WAClB,OAAO;;;UAID;WACN;WACA;WACA;WACA;;WAEA;;WAEA,iBAAiB;;;UAIlB;;WAEC;;WAEA,OAAO;;;UAID,mBAAmB;WACzB;WACA,OAAO;;;UAID,qBAAqB;WAC3B;WACA;WACA,SAAS;;;UAIH;WACN;;WAEA,aAAa;WACb;;;UAIM,oBAAoB;WAC1B;WACA,iBAAiB;;;KAIhB,gBAAgB,aAAa,eAAe;;UAGvC;WACN,SAAS;WACT,GAAG;WACH,GAAG;WACH,iBAAiB;;WAEjB;;WAEA,OAAO;;WAEP;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;;UAIM;;WAEN;;WAEA;;WAEA;;;UAIM;WACN;WACA;;;;;;wBAcK,WAAW,iBAAiB;;;;;;wBA0K5B,OAAO,QAAQ,gBAAgB,SAAQ,QAAQ,iBAAsB;;wBAqBrE,YAAY,QAAQ,gBAAgB,OAAO,eAAe,MAAM,oBAAoB;;wBAQpF,aAAa,QAAQ,gBAAgB,OAAO,yBAAyB;;wBAQrE,aAAa,QAAQ,gBAAgB,OAAO,yBAAyB;;wBAwBrE,WAAW,QAAQ,gBAAgB,OAAO,eAAe,kBAAkB;;wBAK3E,QAAQ,QAAQ,gBAAgB,OAAO,eAAe,MAAM,UAAU,oBAAoB;;wBAO1F,SAAS,QAAQ,gBAAgB,OAAO,eAAe,oBAAoB;;wBAM3E,QAAQ,QAAQ,gBAAgB,OAAO,eAAe,YAAY,OAAO,gBAAgB;;;;;;;;;;;wBAiBzF,UAAU,gBAAgB,gBAAgB,oBAAoB,gBAAgB;;wBAO9E,aAAa,eAAe,mBAAmB;;;;;;;wBA8F/C,OAAO,QAAQ,gBAAgB,OAAO,eAAe,UAAS,cAAmB;;wBAuLjF,YAAY,MAAM,cAAc,OAAO,gBAAgB;;UCnsBtD;;WAEN,UAAU,QAAQ;;WAElB;;WAEA;;;UAIM;;EAEf,SAAS;;EAET;;;;;;;;;;wBAyac,cAAc,MAAM,aAAa,qBAAqB,UAAS,kBAAuB"}
|
package/build/explorer/index.js
CHANGED
|
@@ -440,6 +440,8 @@ function stepsOfView(record, state, panels, cap) {
|
|
|
440
440
|
/**
|
|
441
441
|
* This function gives the data of a view. It does not throw. A request that the record refuses gives the text in
|
|
442
442
|
* `problem`, and no panels. A measure with no model gives only the measured points, and a table model gives cells.
|
|
443
|
+
* A smooth model that is no better than a plain mean also gives only the measured points. A drawn fit claims knowledge that such a model does not have.
|
|
444
|
+
* A table model keeps its cells at any error, because each cell is the mean of measured points.
|
|
443
445
|
*/
|
|
444
446
|
function viewOf(record, state, options = {}) {
|
|
445
447
|
const { budgetMs = 50, stepsCap = 33, now = () => 0 } = options;
|
|
@@ -475,6 +477,17 @@ function viewOf(record, state, options = {}) {
|
|
|
475
477
|
}
|
|
476
478
|
const modelText = model.kind === "table" ? "The model is the mean of each measured cell, so the view shows cells and no smooth surface." : "The model is a smooth fit over all the dimensions.";
|
|
477
479
|
try {
|
|
480
|
+
const heldOut = heldOutError(record, measure.id);
|
|
481
|
+
if (model.kind !== "table" && heldOut.skill !== null && heldOut.skill <= 0) {
|
|
482
|
+
const noBetter = "The model is no better than a plain mean on points that it did not see, so the view shows only the measured points.";
|
|
483
|
+
return {
|
|
484
|
+
...base,
|
|
485
|
+
panels: pointPanels(record, state, levels, facet, tolerance),
|
|
486
|
+
error: heldOut,
|
|
487
|
+
errorText: errorSentence(measure, model, heldOut),
|
|
488
|
+
modelText: noBetter
|
|
489
|
+
};
|
|
490
|
+
}
|
|
478
491
|
const start = now();
|
|
479
492
|
const panels = levels.map((level) => {
|
|
480
493
|
const hold = requestHold(state, facet, level);
|
|
@@ -509,12 +522,11 @@ function viewOf(record, state, options = {}) {
|
|
|
509
522
|
const surface = first?.kind === "surface" ? first : void 0;
|
|
510
523
|
const late = surface !== void 0 && !surface.cells ? nextStepsCap(steps, elapsedMs, budgetMs) : Number.POSITIVE_INFINITY;
|
|
511
524
|
const gridText = surface === void 0 ? "" : gridSentence(surface.surface.x, surface.surface.y, surface.cells, elapsedMs, budgetMs);
|
|
512
|
-
const error = heldOutError(record, measure.id);
|
|
513
525
|
return {
|
|
514
526
|
...base,
|
|
515
527
|
panels,
|
|
516
|
-
error,
|
|
517
|
-
errorText: errorSentence(measure, model,
|
|
528
|
+
error: heldOut,
|
|
529
|
+
errorText: errorSentence(measure, model, heldOut),
|
|
518
530
|
modelText,
|
|
519
531
|
gridText,
|
|
520
532
|
rangeText: rangeSentence(measure, panels),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/explorer/model.ts","../../src/explorer/view.ts"],"sourcesContent":["/**\n * The pure core of the response explorer: the state, the rules of the controls and the data of a view. This module\n * reads a record of the format `response-records/1` only with `@mark1russell7/rigor-statistics`. It has no DOM and no\n * clock of its own, so a test gives it each input.\n *\n * The rules of the controls follow the rules of a conditional dimension. The functions `axisChoices`, `facetChoices`\n * and `holdControls` offer only combinations that `sliceResponse` and `surfaceResponse` accept. The function `settle`\n * gives the nearest good state for any wanted state.\n */\n\nimport {\n heldOutError,\n parseResponseRecord,\n quantile,\n responseCells,\n sliceResponse,\n surfaceResponse,\n whenHolds,\n type ParsedResponseRecord,\n type ResponseBand,\n type ResponseCurvePoint,\n type ResponseDimension,\n type ResponseHeldOutError,\n type ResponseInputValue,\n type ResponseMeasure,\n type ResponseModel,\n type ResponsePoint,\n type ResponseRecord,\n type ResponseSlice,\n type ResponseSurface,\n type ResponseValue,\n} from \"@mark1russell7/rigor-statistics\";\n\n/** The largest number of values on a continuous axis. It is the default of `ResponseViewOptions.steps`. */\nexport const MAX_STEPS = 33;\n/** The smallest number of values on a continuous axis. A smaller grid shows too little of the response. */\nexport const MIN_STEPS = 5;\n/**\n * The largest number of point reads of one view. The field `nearest` of each place reads each point, so the cost of a\n * view is its number of places times the number of points. This number is a first bound, not a measured time.\n * `SURFACE_BUDGET_MS` corrects the grid when a surface takes too long on the device.\n */\nexport const READ_BUDGET = 400_000;\n/** The time of one surface in milliseconds. A longer surface gives a smaller grid for the next surface. */\nexport const SURFACE_BUDGET_MS = 50;\n/** The largest number of panels of one view. */\nexport const MAX_PANELS = 8;\n/** The largest number of stops of a held continuous dimension. */\nexport const MAX_STOPS = 33;\n/** The most levels that a row of buttons shows. A longer group is a select, so it does not push the chart down the page. */\nexport const MAX_CHIPS = 8;\n/** The distance from a measurement, from 0 to 1, at which a band has its weakest color. */\nexport const FADE_END = 0.5;\n/** The number of steps of the color scale of a surface. The CSS classes `rx-h0` to `rx-h8` give the colors. */\nexport const HEAT_STEPS = 9;\n\n/** The choices of a visitor. */\nexport interface ExplorerState {\n /** The id of the measure. */\n readonly measure: string;\n /** The id of the dimension of the horizontal axis. */\n readonly x: string;\n /** The id of the dimension of the vertical axis of a surface. The value `null` gives a curve. */\n readonly y: string | null;\n /** The id of the dimension with one panel for each of its values. The value `null` gives one panel. */\n readonly facet: string | null;\n /** The held value of each dimension. A dimension on an axis keeps its value for a later view. */\n readonly hold: Readonly<Record<string, ResponseValue>>;\n}\n\n/** The two axes of a view. */\nexport type AxisSlot = \"x\" | \"y\";\n\n/** A dimension that a control offers. */\nexport interface DimensionChoice {\n readonly id: string;\n readonly label: string;\n readonly disabled: boolean;\n /** The reason of a disabled choice. A good choice has an empty string. */\n readonly reason: string;\n}\n\n/** A value that a hold control offers. */\nexport interface HoldOption {\n readonly value: ResponseValue;\n readonly text: string;\n readonly disabled: boolean;\n readonly reason: string;\n}\n\n/** The control of one held dimension. */\nexport interface HoldControl {\n readonly id: string;\n readonly label: string;\n /** The value `levels` gives one button for each level. The value `stops` gives a slider over the measured values. */\n readonly kind: \"levels\" | \"stops\";\n /** The value `false` means that the dimension has no value at the held level of its parent. */\n readonly applies: boolean;\n /** The condition of the dimension, as text. A dimension with no condition has an empty string. */\n readonly note: string;\n readonly options: readonly HoldOption[];\n readonly value: ResponseValue;\n}\n\n/** One axis of a chart. A number axis has a linear or log place. A level axis has one equal band for each level. */\nexport interface AxisSpec {\n readonly id: string;\n readonly label: string;\n readonly kind: \"number\" | \"levels\";\n readonly log: boolean;\n /** The two ends of a number axis. */\n readonly range: readonly [number, number];\n /** The levels of a level axis. */\n readonly levels: readonly ResponseValue[];\n}\n\n/** The fields of each kind of panel. */\ninterface PanelBase {\n /** The name of the panel in a view with panels. The only panel of a view has an empty string. */\n readonly title: string;\n /** The value of the facet dimension in this panel. */\n readonly level: ResponseValue | null;\n}\n\n/** A fitted curve with its band and the measured points. */\nexport interface CurvePanel extends PanelBase {\n readonly kind: \"curve\";\n readonly slice: ResponseSlice;\n}\n\n/** A fitted surface. With `cells`, the view shows separate cells with their values, not a smooth surface. */\nexport interface SurfacePanel extends PanelBase {\n readonly kind: \"surface\";\n readonly cells: boolean;\n readonly surface: ResponseSurface;\n}\n\n/** A measured point of a panel with no model. */\nexport interface PlainPoint {\n readonly id: string;\n /** The value of each varied dimension. */\n readonly at: readonly ResponseValue[];\n readonly value: number;\n}\n\n/** The measured points of a measure with no model. */\nexport interface PointsPanel extends PanelBase {\n readonly kind: \"points\";\n readonly points: readonly PlainPoint[];\n}\n\n/** One panel of a view. */\nexport type ExplorerPanel = CurvePanel | SurfacePanel | PointsPanel;\n\n/** The data of one view. */\nexport interface ExplorerView {\n readonly measure: ResponseMeasure;\n readonly x: AxisSpec;\n readonly y: AxisSpec | null;\n readonly panels: readonly ExplorerPanel[];\n /** The value `true` gives a log value axis. */\n readonly log: boolean;\n /** The held-out error. A measure with no model has none. */\n readonly error: ResponseHeldOutError | null;\n /** The held-out error in plain words. */\n readonly errorText: string;\n /** The kind of the model in plain words. */\n readonly modelText: string;\n /** The size of the grid of a surface in plain words. A curve has an empty string. */\n readonly gridText: string;\n /** The places that the range of the measure moved, in plain words. With no such place, this is an empty string. */\n readonly rangeText: string;\n /** The text of a request that the record refused. A good view has an empty string. */\n readonly problem: string;\n /** The number of values on a continuous axis of this view. */\n readonly steps: number;\n /** The time of this view in milliseconds. */\n readonly elapsedMs: number;\n /** The largest number of steps of the next view. */\n readonly nextCap: number;\n}\n\n/** The inputs of `viewOf`. */\nexport interface ViewOptions {\n /** The largest number of steps. The value of `nextCap` of the last view goes here. */\n readonly stepsCap?: number;\n /** The time of a surface in milliseconds. The default is `SURFACE_BUDGET_MS`. */\n readonly budgetMs?: number;\n /** The clock in milliseconds. The default gives 0, so a view with no clock does not drop its grid. */\n readonly now?: () => number;\n}\n\n/** A rectangle of a table of numbers. */\nexport interface NumberTable {\n readonly columns: readonly string[];\n readonly rows: readonly (readonly string[])[];\n}\n\n/** One tick of an axis. */\nexport interface Tick {\n /** The place on the axis, from 0 to 1. */\n readonly place: number;\n readonly text: string;\n}\n\n/**\n * This function reads a record from JSON text or from parsed data. It does not throw: bad data gives faults with\n * their paths.\n */\nexport function openRecord(value: unknown): ParsedResponseRecord {\n if (typeof value !== \"string\") return parseResponseRecord(value);\n try {\n return parseResponseRecord(JSON.parse(value));\n } catch (error) {\n return { ok: false, faults: [{ path: \"\", message: `this text is not JSON: ${String(error)}.` }] };\n }\n}\n\nconst numberText = new Intl.NumberFormat(\"en-US\", { maximumSignificantDigits: 3 });\n\n/** This function gives the text of a value: a number with three significant digits, or the text of a level. */\nexport function formatValue(value: ResponseInputValue): string {\n if (value === null) return \"none\";\n return typeof value === \"number\" ? numberText.format(value) : value;\n}\n\n/** This function gives the dimension with an id that the state or the record names. */\nfunction dimensionOf(record: ResponseRecord, id: string): ResponseDimension {\n const dimension = record.dimensions.find((d) => d.id === id);\n if (dimension === undefined) throw new RangeError(`The record has no dimension \"${id}\".`);\n return dimension;\n}\n\n/** This function gives the measured values of a dimension, with no `null`. */\nfunction measuredValues(record: ResponseRecord, id: string): ResponseValue[] {\n return record.points.flatMap((p) => {\n const value = p.values[id];\n return value === null || value === undefined ? [] : [value];\n });\n}\n\nconst stopCache = new WeakMap<ResponseRecord, Map<string, readonly ResponseValue[]>>();\n\n/** This function gives the distinct measured values of a continuous dimension, in order. */\nfunction distinctNumbers(record: ResponseRecord, id: string): number[] {\n const numbers = measuredValues(record, id).filter((v) => typeof v === \"number\");\n return [...new Set(numbers)].sort((a, b) => a - b);\n}\n\n/**\n * This function gives the values that a visitor can hold: each level, or the measured values of a continuous dimension.\n * With more than `MAX_STOPS` measured values, it gives that number of quantiles of them.\n */\nexport function stopsOf(record: ResponseRecord, dimension: ResponseDimension): readonly ResponseValue[] {\n if (dimension.kind !== \"continuous\") return dimension.levels;\n let stops = stopCache.get(record);\n if (stops === undefined) stopCache.set(record, (stops = new Map()));\n const known = stops.get(dimension.id);\n if (known !== undefined) return known;\n const distinct = distinctNumbers(record, dimension.id);\n const thin = (): number[] => [...new Set(Array.from({ length: MAX_STOPS }, (_, i) => quantile(distinct, i / (MAX_STOPS - 1), \"nearest-rank\")))];\n const found = distinct.length === 0 ? [dimension.range[0]] : distinct.length > MAX_STOPS ? thin() : distinct;\n stops.set(dimension.id, found);\n return found;\n}\n\n/** This function gives the place of a number on a continuous dimension, from 0 to 1. */\nfunction shareOf(dimension: ResponseDimension & { kind: \"continuous\" }, value: number): number {\n const scale = (v: number): number => (dimension.log === true ? Math.log10(v) : v);\n const [low, high] = dimension.range;\n return (scale(value) - scale(low)) / (scale(high) - scale(low));\n}\n\n/**\n * This function gives the option `tolerance` of a view. A dimension with all its measured values as stops needs none.\n * A thinned dimension needs half of its largest gap, so each measured point matches a stop.\n */\nexport function toleranceOf(record: ResponseRecord): number {\n let tolerance = 0;\n for (const dimension of record.dimensions) {\n if (dimension.kind !== \"continuous\") continue;\n const stops = stopsOf(record, dimension) as readonly number[];\n if (stops.length === distinctNumbers(record, dimension.id).length) continue;\n for (let i = 1; i < stops.length; i++) {\n const gap = shareOf(dimension, stops[i] as number) - shareOf(dimension, stops[i - 1] as number);\n tolerance = Math.max(tolerance, gap / 2);\n }\n }\n return tolerance;\n}\n\n/** This function gives the usual value of a dimension: the measured median, or the most common level in `among`. */\nfunction usualValue(record: ResponseRecord, dimension: ResponseDimension, among?: readonly ResponseValue[]): ResponseValue {\n const values = measuredValues(record, dimension.id);\n if (dimension.kind === \"continuous\") {\n const numbers = values.filter((v) => typeof v === \"number\");\n return numbers.length === 0 ? dimension.range[0] : quantile(numbers, 0.5, \"nearest-rank\");\n }\n const levels: readonly ResponseValue[] = among ?? dimension.levels;\n const count = (level: ResponseValue): number => values.filter((v) => v === level).length;\n return levels.reduce((best, level) => (count(level) > count(best) ? level : best), levels[0] as ResponseValue);\n}\n\n/** This function gives the stop of a dimension that is nearest to a value, or `undefined` for a value of no use. */\nfunction nearestStop(record: ResponseRecord, dimension: ResponseDimension, value: ResponseValue | undefined): ResponseValue | undefined {\n const stops = stopsOf(record, dimension);\n if (value === undefined) return undefined;\n if (dimension.kind !== \"continuous\") return stops.includes(value) ? value : undefined;\n if (typeof value !== \"number\") return undefined;\n const far = (stop: ResponseValue): number => Math.abs(shareOf(dimension, stop as number) - shareOf(dimension, value));\n return stops.reduce((best, stop) => (far(stop) < far(best) ? stop : best));\n}\n\n/** This function gives the levels that the parent of each varied conditional dimension needs. */\nfunction neededLevels(record: ResponseRecord, varied: readonly string[]): Map<string, readonly ResponseValue[]> {\n const needed = new Map<string, readonly ResponseValue[]>();\n for (const id of varied) {\n const when = dimensionOf(record, id).when;\n if (when === undefined) continue;\n const earlier = needed.get(when.dimension);\n needed.set(when.dimension, earlier === undefined ? when.levels : earlier.filter((level) => when.levels.includes(level)));\n }\n return needed;\n}\n\n/** This function gives the condition of a dimension as a phrase of a sentence. */\nfunction whenText(record: ResponseRecord, dimension: ResponseDimension): string {\n const when = dimension.when;\n if (when === undefined) return \"\";\n return `only when ${dimensionOf(record, when.dimension).label} is ${when.levels.map(formatValue).join(\" or \")}`;\n}\n\nconst variedOf = (state: Pick<ExplorerState, \"x\" | \"y\">): string[] => (state.y === null ? [state.x] : [state.x, state.y]);\n\n/** This function gives the values of a dimension in panels, inside the needs of the varied dimensions. */\nfunction panelLevels(record: ResponseRecord, state: Pick<ExplorerState, \"x\" | \"y\">, id: string): readonly ResponseValue[] {\n const stops = stopsOf(record, dimensionOf(record, id));\n const needed = neededLevels(record, variedOf(state)).get(id);\n return needed === undefined ? stops : stops.filter((value) => needed.includes(value));\n}\n\n/** This function gives the reason that a dimension cannot be in panels. A good dimension gives an empty string. */\nfunction facetBlock(record: ResponseRecord, state: Pick<ExplorerState, \"x\" | \"y\" | \"hold\">, dimension: ResponseDimension): string {\n if (variedOf(state).includes(dimension.id)) return \"It is on an axis\";\n const when = dimension.when;\n if (when !== undefined && !variedOf(state).includes(when.dimension) && !when.levels.includes(state.hold[when.dimension] as ResponseValue)) return `It applies ${whenText(record, dimension)}`;\n const count = panelLevels(record, state, dimension.id).length;\n if (count > MAX_PANELS) return `It has ${count} values, and a view has ${MAX_PANELS} panels or fewer`;\n if (count < 2) return \"It has one value here\";\n return \"\";\n}\n\n/** This function gives the reason that a dimension cannot go on an axis. A good dimension gives an empty string. */\nfunction axisBlock(record: ResponseRecord, state: ExplorerState, slot: AxisSlot, dimension: ResponseDimension): string {\n const otherId = slot === \"x\" ? state.y : state.x;\n if (dimension.id === otherId) return \"It is on the other axis\";\n const other = otherId === null ? undefined : dimensionOf(record, otherId);\n if (other?.when?.dimension === dimension.id) return `${other.label} needs it held`;\n const when = dimension.when;\n if (when === undefined) return \"\";\n const parent = dimensionOf(record, when.dimension);\n if (parent.id === otherId) return `It needs ${parent.label} held`;\n const shared = other?.when?.dimension === parent.id ? when.levels.filter((level) => other.when?.levels.includes(level) === true) : when.levels;\n const inView = parent.id === state.facet ? stopsOf(record, parent) : [state.hold[parent.id] as ResponseValue];\n return inView.some((level) => shared.includes(level)) ? \"\" : `It applies ${whenText(record, dimension)}`;\n}\n\n/** This function gives the first dimension with no condition, and a continuous dimension before another kind. */\nfunction firstAxis(record: ResponseRecord): string {\n const plain = record.dimensions.filter((d) => d.when === undefined);\n const chosen = plain.find((d) => d.kind === \"continuous\") ?? plain[0] ?? record.dimensions[0];\n return (chosen as ResponseDimension).id;\n}\n\n/**\n * This function gives the nearest good state for a wanted state. Each unknown or missing field takes its usual value.\n * A parent moves to a level that a varied conditional dimension needs. A combination that a view refuses loses its\n * second axis or its panels.\n */\nexport function settle(record: ResponseRecord, wanted: Partial<ExplorerState> = {}): ExplorerState {\n const known = (id: string | null | undefined): boolean => id !== null && id !== undefined && record.dimensions.some((d) => d.id === id);\n const measure = record.measures.some((m) => m.id === wanted.measure) ? (wanted.measure as string) : (record.measures[0]?.id ?? \"\");\n const x = known(wanted.x) ? (wanted.x as string) : firstAxis(record);\n const parentOf = (id: string): string | undefined => dimensionOf(record, id).when?.dimension;\n let y = known(wanted.y) && wanted.y !== x ? (wanted.y as string) : null;\n if (y !== null && (parentOf(y) === x || parentOf(x) === y || [...neededLevels(record, [x, y]).values()].some((levels) => levels.length === 0))) y = null;\n\n const hold: Record<string, ResponseValue> = {};\n for (const dimension of record.dimensions) hold[dimension.id] = nearestStop(record, dimension, wanted.hold?.[dimension.id]) ?? usualValue(record, dimension);\n\n const facetId = known(wanted.facet) ? (wanted.facet as string) : null;\n const facet = facetId !== null && facetBlock(record, { x, y, hold }, dimensionOf(record, facetId)) === \"\" ? facetId : null;\n for (const [parent, levels] of neededLevels(record, variedOf({ x, y }))) {\n if (parent === facet || levels.includes(hold[parent] as ResponseValue)) continue;\n hold[parent] = usualValue(record, dimensionOf(record, parent), levels);\n }\n return { measure, x, y, facet: facet !== null && facetBlock(record, { x, y, hold }, dimensionOf(record, facet)) === \"\" ? facet : null, hold };\n}\n\n/** This function gives each dimension as a choice for an axis. A disabled choice tells its reason. */\nexport function axisChoices(record: ResponseRecord, state: ExplorerState, slot: AxisSlot): readonly DimensionChoice[] {\n return record.dimensions.map((d) => {\n const reason = axisBlock(record, state, slot, d);\n return { id: d.id, label: d.label, disabled: reason !== \"\", reason };\n });\n}\n\n/** This function gives each dimension as a choice for panels. A disabled choice tells its reason. */\nexport function facetChoices(record: ResponseRecord, state: ExplorerState): readonly DimensionChoice[] {\n return record.dimensions.map((d) => {\n const reason = facetBlock(record, state, d);\n return { id: d.id, label: d.label, disabled: reason !== \"\", reason };\n });\n}\n\n/** This function gives the control of each held dimension. A dimension on an axis or in panels has no control. */\nexport function holdControls(record: ResponseRecord, state: ExplorerState): readonly HoldControl[] {\n const needed = neededLevels(record, variedOf(state));\n const held = record.dimensions.filter((d) => !variedOf(state).includes(d.id) && d.id !== state.facet);\n return held.map((d) => {\n const parent = d.when?.dimension;\n const open = parent === undefined || parent === state.facet || variedOf(state).includes(parent);\n const applies = open || d.when?.levels.includes(state.hold[parent as string] as ResponseValue) === true;\n const levels = needed.get(d.id);\n const options = stopsOf(record, d).map((value): HoldOption => {\n const locked = levels !== undefined && !levels.includes(value);\n const reason = !applies ? `It applies ${whenText(record, d)}` : locked ? \"A varied dimension has no value at this level\" : \"\";\n return { value, text: formatValue(value), disabled: reason !== \"\", reason };\n });\n const note = d.when === undefined ? \"\" : `Applies ${whenText(record, d)}`;\n return { id: d.id, label: d.label, kind: d.kind === \"continuous\" ? \"stops\" : \"levels\", applies, note, options, value: state.hold[d.id] as ResponseValue };\n });\n}\n\n/** This function gives the form of a group of levels. */\nexport function levelForm(count: number): \"chips\" | \"select\" {\n return count > MAX_CHIPS ? \"select\" : \"chips\";\n}\n\n/** This function gives the state with a new measure. */\nexport function setMeasure(record: ResponseRecord, state: ExplorerState, measure: string): ExplorerState {\n return settle(record, { ...state, measure });\n}\n\n/** This function gives the state with a new axis. It does not take a disabled choice. The value `null` removes the y axis. */\nexport function setAxis(record: ResponseRecord, state: ExplorerState, slot: AxisSlot, id: string | null): ExplorerState {\n if (id === null) return slot === \"y\" ? settle(record, { ...state, y: null }) : state;\n if (axisBlock(record, state, slot, dimensionOf(record, id)) !== \"\") return state;\n return settle(record, { ...state, [slot]: id, facet: state.facet === id ? null : state.facet });\n}\n\n/** This function gives the state with new panels. It does not take a disabled choice. The value `null` gives one panel. */\nexport function setFacet(record: ResponseRecord, state: ExplorerState, id: string | null): ExplorerState {\n if (id !== null && facetBlock(record, state, dimensionOf(record, id)) !== \"\") return state;\n return settle(record, { ...state, facet: id });\n}\n\n/** This function gives the state with a new held value. It does not take a disabled value. */\nexport function setHold(record: ResponseRecord, state: ExplorerState, id: string, value: ResponseValue): ExplorerState {\n const control = holdControls(record, state).find((c) => c.id === id);\n const option = control?.options.find((o) => o.value === value);\n if (option === undefined || option.disabled) return state;\n return settle(record, { ...state, hold: { ...state.hold, [id]: value } });\n}\n\n/**\n * This function gives the number of steps of a view, from the number of points, before the call. The field `nearest`\n * reads each point at each place, so the number of places comes from `READ_BUDGET`.\n *\n * @param points - The number of points of the record.\n * @param panels - The number of panels of the view.\n * @param continuous - The number of continuous axes of the view.\n * @param levels - The number of levels of a level axis of a surface, or 1.\n * @param cap - The largest result.\n */\nexport function planSteps(points: number, panels: number, continuous: number, levels: number, cap: number = MAX_STEPS): number {\n const places = READ_BUDGET / (Math.max(1, points) * Math.max(1, panels));\n const room = continuous === 2 ? Math.sqrt(places) : places / Math.max(1, levels);\n return Math.max(MIN_STEPS, Math.min(cap, MAX_STEPS, Math.floor(room)));\n}\n\n/** This function gives the cap of the next view: a smaller grid when this surface took more than the budget. */\nexport function nextStepsCap(steps: number, elapsedMs: number, budgetMs: number): number {\n if (elapsedMs <= budgetMs) return Number.POSITIVE_INFINITY;\n return Math.max(MIN_STEPS, Math.min(steps - 1, Math.floor(steps * Math.sqrt(budgetMs / elapsedMs))));\n}\n\n/** This function gives the axis of a dimension. */\nexport function axisOf(dimension: ResponseDimension): AxisSpec {\n const { id, label, unit } = dimension;\n const name = unit === \"\" ? label : `${label} (${unit})`;\n if (dimension.kind === \"continuous\") return { id, label: name, kind: \"number\", log: dimension.log === true, range: dimension.range, levels: [] };\n return { id, label: name, kind: \"levels\", log: false, range: [0, 1], levels: dimension.levels };\n}\n\n/** This function gives the place of a value on an axis, from 0 to 1. A value outside a number axis goes past the ends. */\nexport function placeOn(axis: AxisSpec, value: ResponseValue): number {\n if (axis.kind === \"levels\") return (axis.levels.indexOf(value) + 0.5) / axis.levels.length;\n const scale = (v: number): number => (axis.log ? Math.log10(v) : v);\n const [low, high] = axis.range;\n return (scale(value as number) - scale(low)) / (scale(high) - scale(low));\n}\n\n/** This function gives true for a point that matches the held values, with the rules of `sliceResponse`. */\nfunction pointMatches(record: ResponseRecord, point: ResponsePoint, measure: string, varied: readonly string[], hold: Readonly<Record<string, ResponseValue>>, tolerance: number): boolean {\n if (typeof point.measures[measure] !== \"number\") return false;\n return record.dimensions.every((d) => {\n const value = point.values[d.id] ?? null;\n if (varied.includes(d.id)) return value !== null;\n const wanted = whenHolds(d, point.values) ? (hold[d.id] as ResponseValue) : null;\n if (typeof value !== \"number\" || typeof wanted !== \"number\" || d.kind !== \"continuous\") return value === wanted;\n return Math.abs(shareOf(d, value) - shareOf(d, wanted)) <= tolerance;\n });\n}\n\n/** This function gives the error of a measure in plain words. */\nexport function errorSentence(measure: ResponseMeasure, model: ResponseModel, error: ResponseHeldOutError): string {\n const unit = measure.unit === \"\" ? \"\" : ` ${measure.unit}`;\n const amount = (value: number): string => (model.scale === \"log\" ? `a factor of ${formatValue(10 ** value)}` : `${formatValue(value)}${unit}`);\n const seen = `On ${error.n} points that each fit did not see, over ${error.folds} folds, the model misses by ${amount(error.mae)} on average.`;\n const base = `A plain mean misses by ${amount(error.baselineMae)}.`;\n if (error.skill === null) return `${seen} ${base}`;\n return error.skill > 0 ? `${seen} ${base} The model removes ${Math.round(error.skill * 100)}% of that miss.` : `${seen} ${base} The model is no better than the mean.`;\n}\n\n/** This function gives the name of a panel. */\nconst panelTitle = (facet: ResponseDimension | undefined, level: ResponseValue | null): string => (facet === undefined || level === null ? \"\" : `${facet.label}: ${formatValue(level)}`);\n\n/** This function gives the panels of a measure with no model: the measured points that match the held values. */\nfunction pointPanels(record: ResponseRecord, state: ExplorerState, levels: readonly (ResponseValue | null)[], facet: ResponseDimension | undefined, tolerance: number): ExplorerPanel[] {\n const varied = variedOf(state);\n return levels.map((level) => {\n const hold = level === null || facet === undefined ? state.hold : { ...state.hold, [facet.id]: level };\n const points = record.points.flatMap((p): PlainPoint[] => {\n if (!pointMatches(record, p, state.measure, varied, hold, tolerance)) return [];\n return [{ id: p.id, at: varied.map((id) => p.values[id] as ResponseValue), value: p.measures[state.measure] as number }];\n });\n return { kind: \"points\", title: panelTitle(facet, level), level, points };\n });\n}\n\n/** This function gives the held values of a request: each dimension that does not vary. */\nfunction requestHold(state: ExplorerState, facet: ResponseDimension | undefined, level: ResponseValue | null): Record<string, ResponseValue> {\n const varied = variedOf(state);\n const hold = Object.fromEntries(Object.entries(state.hold).filter(([id]) => !varied.includes(id)));\n return facet === undefined || level === null ? hold : { ...hold, [facet.id]: level };\n}\n\n/** This function gives the text of the size of a grid. */\nfunction gridSentence(x: readonly ResponseValue[], y: readonly ResponseValue[], cells: boolean, elapsedMs: number, budgetMs: number): string {\n if (cells) return `The grid has ${x.length} by ${y.length} measured levels.`;\n const size = `The grid has ${x.length} by ${y.length} places.`;\n return elapsedMs > budgetMs ? `${size} This surface took ${Math.round(elapsedMs)} ms, so the next grid is smaller.` : size;\n}\n\n/** This function gives the text of the places that a range moved. A view with no such place gives an empty string. */\nfunction rangeSentence(measure: ResponseMeasure, panels: readonly ExplorerPanel[]): string {\n const moved = panels.reduce((count, panel) => count + (panel.kind === \"curve\" ? panel.slice.clipped : panel.kind === \"surface\" ? panel.surface.clipped : 0), 0);\n if (moved === 0 || measure.range === undefined) return \"\";\n return `At ${moved} ${moved === 1 ? \"place\" : \"places\"}, the view stops at the range of the measure, ${measure.range[0]} to ${measure.range[1]}.`;\n}\n\n/** This function gives the steps of a view from its axes and the plan of `planSteps`. */\nfunction stepsOfView(record: ResponseRecord, state: ExplorerState, panels: number, cap: number): number {\n const continuous = variedOf(state).filter((id) => dimensionOf(record, id).kind === \"continuous\").length;\n // A count at 2 steps, less the 2 of each continuous axis, leaves the levels of the other axes.\n const levels = responseCells(record, state.y === null ? state.x : [state.x, state.y], 2) / 2 ** continuous;\n return planSteps(record.points.length, panels, continuous, levels, cap);\n}\n\n/**\n * This function gives the data of a view. It does not throw. A request that the record refuses gives the text in\n * `problem`, and no panels. A measure with no model gives only the measured points, and a table model gives cells.\n */\nexport function viewOf(record: ResponseRecord, state: ExplorerState, options: ViewOptions = {}): ExplorerView {\n const { budgetMs = SURFACE_BUDGET_MS, stepsCap = MAX_STEPS, now = (): number => 0 } = options;\n const measure = record.measures.find((m) => m.id === state.measure) ?? (record.measures[0] as ResponseMeasure);\n const model = record.models.find((m) => m.measure === measure.id);\n const x = axisOf(dimensionOf(record, state.x));\n const y = state.y === null ? null : axisOf(dimensionOf(record, state.y));\n const facet = state.facet === null ? undefined : dimensionOf(record, state.facet);\n const levels = facet === undefined ? [null] : panelLevels(record, state, facet.id);\n const steps = stepsOfView(record, state, levels.length, stepsCap);\n const tolerance = toleranceOf(record);\n const base = { measure, x, y, log: model?.scale === \"log\", steps, elapsedMs: 0, nextCap: stepsCap, gridText: \"\", rangeText: \"\", problem: \"\" };\n\n if (model === undefined) {\n const modelText = \"This measure has no valid model in the record, so the view shows only the measured points.\";\n return { ...base, panels: pointPanels(record, state, levels, facet, tolerance), error: null, errorText: \"\", modelText };\n }\n const modelText = model.kind === \"table\" ? \"The model is the mean of each measured cell, so the view shows cells and no smooth surface.\" : \"The model is a smooth fit over all the dimensions.\";\n try {\n const start = now();\n const panels = levels.map((level): ExplorerPanel => {\n const hold = requestHold(state, facet, level);\n const title = panelTitle(facet, level);\n if (state.y === null) return { kind: \"curve\", title, level, slice: sliceResponse(record, measure.id, { vary: state.x, hold, steps, tolerance }) };\n const surface = surfaceResponse(record, measure.id, { vary: [state.x, state.y], hold, steps, tolerance });\n return { kind: \"surface\", title, level, cells: model.kind === \"table\" || (x.kind === \"levels\" && y?.kind === \"levels\"), surface };\n });\n const elapsedMs = Math.max(0, now() - start);\n const first = panels[0];\n const surface = first?.kind === \"surface\" ? first : undefined;\n const late = surface !== undefined && !surface.cells ? nextStepsCap(steps, elapsedMs, budgetMs) : Number.POSITIVE_INFINITY;\n const gridText = surface === undefined ? \"\" : gridSentence(surface.surface.x, surface.surface.y, surface.cells, elapsedMs, budgetMs);\n const error = heldOutError(record, measure.id);\n return { ...base, panels, error, errorText: errorSentence(measure, model, error), modelText, gridText, rangeText: rangeSentence(measure, panels), elapsedMs, nextCap: Math.min(stepsCap, late) };\n } catch (error) {\n return { ...base, panels: [], error: null, errorText: \"\", modelText, problem: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/** This function gives the strength of the band at a distance from a measurement: 1 at a measurement, 0.15 far away. */\nexport function fadeOf(nearest: number): number {\n return 1 - 0.85 * Math.min(1, nearest / FADE_END);\n}\n\n/** This function gives the share of the neutral veil of a surface cell at a distance from a measurement. */\nexport function veilOf(nearest: number): number {\n return 0.8 * Math.min(1, nearest / FADE_END);\n}\n\n/** This function gives a round step for a range and a tick count: 1, 2 or 5 times a power of 10. */\nfunction roundStep(span: number, count: number): number {\n const raw = span / Math.max(1, count);\n const power = 10 ** Math.floor(Math.log10(raw));\n const share = raw / power;\n return (share <= 1 ? 1 : share <= 2 ? 2 : share <= 5 ? 5 : 10) * power;\n}\n\n/** This function gives round numbers in a range, for approximately `count` ticks. */\nfunction roundNumbers(low: number, high: number, count: number): number[] {\n if (!(high > low)) return [low];\n const step = roundStep(high - low, count);\n const out: number[] = [];\n for (let i = Math.ceil(low / step - 1e-9); i * step <= high + step * 1e-9; i++) out.push(Number((i * step).toPrecision(12)));\n return out;\n}\n\n/** This function gives the values 1, 2 and 5 times each power of 10 in a range, for approximately `count` ticks. */\nfunction logNumbers(low: number, high: number, count: number): number[] {\n const out: number[] = [];\n for (let power = Math.floor(Math.log10(low)); power <= Math.ceil(Math.log10(high)); power++) {\n for (const factor of [1, 2, 5]) {\n const value = Number((factor * 10 ** power).toPrecision(12));\n if (value >= low * (1 - 1e-9) && value <= high * (1 + 1e-9)) out.push(value);\n }\n }\n const powers = out.filter((value) => Number.isInteger(Math.log10(value)));\n return out.length > count && powers.length >= 2 ? powers : out;\n}\n\n/** This function gives the ticks of a number range. A log range with too few round values gives linear round values. */\nexport function numberTicks(low: number, high: number, log: boolean, count: number): readonly Tick[] {\n const scale = (v: number): number => (log ? Math.log10(v) : v);\n const logged = log ? logNumbers(low, high, count) : [];\n const values = logged.length >= 3 ? logged : roundNumbers(low, high, count);\n return values.map((value) => ({ place: high > low ? (scale(value) - scale(low)) / (scale(high) - scale(low)) : 0.5, text: formatValue(value) }));\n}\n\n/** This function gives the ticks of an axis. */\nexport function axisTicks(axis: AxisSpec, count: number): readonly Tick[] {\n if (axis.kind === \"number\") return numberTicks(axis.range[0], axis.range[1], axis.log, count);\n return axis.levels.map((level) => ({ place: placeOn(axis, level), text: formatValue(level) }));\n}\n\n/** This function gives the values of one panel that the value axis must show. */\nfunction panelValues(panel: ExplorerPanel, varied: number): number[] {\n if (panel.kind === \"points\") return varied === 1 ? panel.points.map((p) => p.value) : [];\n if (panel.kind === \"curve\") return [...panel.slice.curve.flatMap((c) => [c.low, c.high]), ...panel.slice.points.map((p) => p.value)];\n return [];\n}\n\n/**\n * This function gives the two ends of the value axis of a curve view. All the panels of a view share them, so two\n * panels compare by eye. A range of one value grows, so the axis keeps a length.\n */\nexport function valueRange(view: ExplorerView): readonly [number, number] {\n const values = view.panels.flatMap((panel) => panelValues(panel, view.y === null ? 1 : 2)).filter((v) => Number.isFinite(v) && (!view.log || v > 0));\n if (values.length === 0) return view.log ? [1, 10] : [0, 1];\n const low = Math.min(...values);\n const high = Math.max(...values);\n if (view.log) {\n const margin = high > low ? (high / low) ** 0.05 : 2;\n return [low / margin, high * margin];\n }\n const margin = high > low ? (high - low) * 0.05 : Math.max(Math.abs(low) * 0.1, 1);\n return [low - margin, high + margin];\n}\n\n/** This function gives each fitted value of a surface view, with the values of a view of plain points. */\nfunction heatValues(view: ExplorerView): number[] {\n return view.panels.flatMap((panel) => {\n if (panel.kind === \"surface\") return panel.surface.cells.flatMap((row) => row.map((cell) => cell.value));\n return panel.kind === \"points\" ? panel.points.map((p) => p.value) : [];\n });\n}\n\n/** This function gives the two ends of the color scale of a surface view. All the panels share them. */\nexport function heatRange(view: ExplorerView): readonly [number, number] {\n const values = heatValues(view).filter((v) => Number.isFinite(v) && (!view.log || v > 0));\n if (values.length === 0) return [0, 1];\n return [Math.min(...values), Math.max(...values)];\n}\n\n/** This function gives the step of the color scale of a value, from 0 to `HEAT_STEPS - 1`. */\nexport function heatStep(value: number, range: readonly [number, number], log: boolean): number {\n const [low, high] = range;\n if (!(high > low)) return Math.floor(HEAT_STEPS / 2);\n const share = log ? (Math.log10(value) - Math.log10(low)) / (Math.log10(high) - Math.log10(low)) : (value - low) / (high - low);\n return Math.max(0, Math.min(HEAT_STEPS - 1, Math.floor(share * HEAT_STEPS)));\n}\n\n/** This function gives the edges of the cells around places on an axis, from 0 to 1. There is one more edge than places. */\nexport function cellEdges(places: readonly number[]): readonly number[] {\n const inner = places.slice(1).map((place, i) => (place + (places[i] as number)) / 2);\n return [0, ...inner, 1];\n}\n\n/** A point of a path, in the pixels of a chart. */\nexport type Pixel = readonly [number, number];\n\n/** This function gives the path of a line through pixels. */\nexport function linePath(pixels: readonly Pixel[]): string {\n return pixels.map(([x, y], i) => `${i === 0 ? \"M\" : \"L\"}${x.toFixed(1)} ${y.toFixed(1)}`).join(\"\");\n}\n\n/** This function gives the closed path of a band between its upper and its lower pixels. */\nexport function bandPath(upper: readonly Pixel[], lower: readonly Pixel[]): string {\n return `${linePath([...upper, ...[...lower].reverse()])}Z`;\n}\n\n/** This function gives the distance from a measurement in plain words. */\nfunction nearText(nearest: number): string {\n return nearest === 0 ? \"A point was measured here.\" : `The nearest measured point is ${Math.round(nearest * 100)}% of an axis away.`;\n}\n\n/** This function gives the text of one place of a band. */\nfunction bandText(band: ResponseBand): string {\n return `fitted ${formatValue(band.value)}, band ${formatValue(band.low)} to ${formatValue(band.high)}. ${nearText(band.nearest)}`;\n}\n\n/** This function gives the text of one place of a curve. */\nexport function curveText(axis: AxisSpec, place: ResponseCurvePoint): string {\n return `${axis.label} ${formatValue(place.at)}: ${bandText(place)}`;\n}\n\n/** This function gives the text of one place of a surface. */\nexport function cellText(x: AxisSpec, y: AxisSpec, atX: ResponseValue, atY: ResponseValue, band: ResponseBand): string {\n return `${x.label} ${formatValue(atX)}, ${y.label} ${formatValue(atY)}: ${bandText(band)}`;\n}\n\n/** This function gives the numbers of a panel: each place of a curve, or the measured points of a surface. */\nexport function numberTable(view: ExplorerView, panel: ExplorerPanel): NumberTable {\n const axes = view.y === null ? [view.x.label] : [view.x.label, view.y.label];\n if (panel.kind === \"curve\") {\n const rows = panel.slice.curve.map((c) => [formatValue(c.at), formatValue(c.value), formatValue(c.low), formatValue(c.high), `${Math.round(c.nearest * 100)}%`]);\n return { columns: [view.x.label, \"Fitted\", \"Low\", \"High\", \"Distance\"], rows };\n }\n const points: readonly { readonly at: readonly ResponseValue[]; readonly value: number }[] = panel.kind === \"points\" ? panel.points : panel.surface.points;\n return { columns: [...axes, \"Measured\"], rows: points.map((p) => [...p.at.map(formatValue), formatValue(p.value)]) };\n}\n","/// <reference lib=\"dom\" />\n/**\n * The DOM view of the response explorer. This module draws SVG with no framework. The core in `model.ts` gives each\n * rule and each number, and this module connects the core to the page.\n */\n\nimport { h, type Child } from \"../chrome.ts\";\nimport {\n axisChoices,\n axisTicks,\n bandPath,\n cellEdges,\n cellText,\n curveText,\n facetChoices,\n fadeOf,\n formatValue,\n heatRange,\n heatStep,\n HEAT_STEPS,\n holdControls,\n levelForm,\n linePath,\n MAX_STEPS,\n numberTable,\n numberTicks,\n openRecord,\n placeOn,\n setAxis,\n setFacet,\n setHold,\n setMeasure,\n settle,\n SURFACE_BUDGET_MS,\n valueRange,\n veilOf,\n viewOf,\n type AxisSpec,\n type CurvePanel,\n type DimensionChoice,\n type ExplorerPanel,\n type ExplorerState,\n type ExplorerView,\n type HoldControl,\n type Pixel,\n type PointsPanel,\n type SurfacePanel,\n type Tick,\n} from \"./model.ts\";\nimport type { ResponseRecord, ResponseValue } from \"@mark1russell7/rigor-statistics\";\n\n/** The options of `mountExplorer`. */\nexport interface ExplorerOptions {\n /** The first state. The explorer corrects a state that a record refuses. */\n readonly initial?: Partial<ExplorerState>;\n /** The time of a surface in milliseconds. The default is `SURFACE_BUDGET_MS`. */\n readonly budgetMs?: number;\n /** The clock in milliseconds. The default is `performance.now`. */\n readonly now?: () => number;\n}\n\n/** The result of `mountExplorer`. */\nexport interface ExplorerHandle {\n /** This method gives the choices of the visitor. It gives `null` for a record with faults. */\n state(): ExplorerState | null;\n /** This method removes the explorer from its host. */\n destroy(): void;\n}\n\nconst SVG = \"http://www.w3.org/2000/svg\";\n/** The most faults that the view lists. */\nconst MAX_FAULTS = 20;\n/** The width of a chart with no layout, for example in a test. */\nconst FALLBACK_WIDTH = 640;\nconst MARGIN = { top: 10, right: 14, bottom: 42, left: 50 };\n/** The height of a line of text of an axis, in pixels. */\nconst CHAR_WIDTH = 6.4;\n\nlet mounts = 0;\n\n/** This function makes an SVG element with attributes and children. */\nfunction s(tag: string, attrs: Readonly<Record<string, string | number>>, ...children: readonly (Node | string)[]): SVGElement {\n const el = document.createElementNS(SVG, tag);\n for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, String(value));\n el.append(...children);\n return el;\n}\n\n/** The plot of a chart: the pixels of its area and of its axes. */\ninterface Plot {\n readonly width: number;\n readonly height: number;\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** This function gives the plot of a chart. Long level names need room for their turned text. */\nfunction plotOf(width: number, height: number, view: ExplorerView): Plot {\n const turned = turnedLevels(view.x, width - MARGIN.left - MARGIN.right);\n const longest = Math.max(0, ...view.x.levels.map((level) => formatValue(level).length));\n const bottom = height - MARGIN.bottom - (turned ? Math.min(60, longest * CHAR_WIDTH * 0.7) : 0);\n const left = view.y?.kind === \"levels\" ? Math.min(110, Math.max(MARGIN.left, 12 + Math.max(...view.y.levels.map((level) => formatValue(level).length)) * CHAR_WIDTH)) : MARGIN.left;\n return { width, height, left, top: MARGIN.top, right: width - MARGIN.right, bottom };\n}\n\n/** This function gives true when the levels of an axis do not fit side by side. */\nfunction turnedLevels(axis: AxisSpec, room: number): boolean {\n if (axis.kind !== \"levels\") return false;\n const longest = Math.max(0, ...axis.levels.map((level) => formatValue(level).length));\n return (longest + 1) * CHAR_WIDTH > room / Math.max(1, axis.levels.length);\n}\n\n/** This function gives the ticks of an axis that fit in a length. */\nfunction fittedTicks(axis: AxisSpec, length: number): readonly Tick[] {\n return axisTicks(axis, Math.max(2, Math.floor(length / 70)));\n}\n\n/** This function draws the horizontal axis. */\nfunction xAxis(plot: Plot, axis: AxisSpec): SVGElement {\n const length = plot.right - plot.left;\n const turned = turnedLevels(axis, length);\n const ticks = fittedTicks(axis, length).map((tick) => {\n const x = plot.left + tick.place * length;\n const label = turned\n ? s(\"text\", { class: \"rx-tick\", x, y: plot.bottom + 14, \"text-anchor\": \"end\", transform: `rotate(-35 ${x} ${plot.bottom + 14})` }, tick.text)\n : s(\"text\", { class: \"rx-tick\", x, y: plot.bottom + 15, \"text-anchor\": x + (tick.text.length * CHAR_WIDTH) / 2 > plot.width ? \"end\" : \"middle\" }, tick.text);\n return s(\"g\", {}, s(\"line\", { class: \"rx-axis\", x1: x, x2: x, y1: plot.bottom, y2: plot.bottom + 4 }), label);\n });\n const name = s(\"text\", { class: \"rx-axis-name\", x: (plot.left + plot.right) / 2, y: plot.height - 6, \"text-anchor\": \"middle\" }, axis.log ? `${axis.label}, log scale` : axis.label);\n return s(\"g\", {}, s(\"line\", { class: \"rx-axis\", x1: plot.left, x2: plot.right, y1: plot.bottom, y2: plot.bottom }), ...ticks, name);\n}\n\n/** This function draws the value axis with its grid lines. */\nfunction valueAxis(plot: Plot, ticks: readonly Tick[]): SVGElement {\n const length = plot.bottom - plot.top;\n const lines = ticks.map((tick) => {\n const y = plot.bottom - tick.place * length;\n return s(\"g\", {}, s(\"line\", { class: \"rx-grid\", x1: plot.left, x2: plot.right, y1: y, y2: y }), s(\"text\", { class: \"rx-tick\", x: plot.left - 6, y: y + 4, \"text-anchor\": \"end\" }, tick.text));\n });\n return s(\"g\", {}, ...lines);\n}\n\n/** This function draws the vertical axis of a surface. */\nfunction surfaceAxis(plot: Plot, axis: AxisSpec): SVGElement {\n const length = plot.bottom - plot.top;\n const ticks = axisTicks(axis, Math.max(2, Math.floor(length / 45))).map((tick) => {\n const y = plot.bottom - tick.place * length;\n return s(\"text\", { class: \"rx-tick\", x: plot.left - 6, y: y + 4, \"text-anchor\": \"end\" }, tick.text);\n });\n return s(\"g\", {}, ...ticks);\n}\n\n/** The scale of the value axis of a view. */\ninterface ValueScale {\n readonly range: readonly [number, number];\n readonly log: boolean;\n}\n\n/** This function gives the place of a value on the value axis, from 0 to 1. */\nfunction valuePlace(scale: ValueScale, value: number): number {\n const [low, high] = scale.range;\n if (scale.log) return (Math.log10(Math.max(value, low)) - Math.log10(low)) / (Math.log10(high) - Math.log10(low));\n return (value - low) / (high - low);\n}\n\n/** This function gives a small steady offset for a dot from its id, so the dots of one level do not all overlap. */\nfunction jitter(id: string, room: number): number {\n let hash = 7;\n for (const char of id) hash = (hash * 31 + (char.codePointAt(0) ?? 0)) % 1009;\n return (hash / 1008 - 0.5) * room;\n}\n\n/** The handler of a panel: it moves the mark of the cursor and it gives the text of a place. */\ninterface Cursor {\n /** The number of places across and up. */\n readonly columns: number;\n readonly rows: number;\n /** This method gives the place at a pixel. */\n at(x: number, y: number): readonly [number, number];\n /** This method moves the mark and gives the text of the place. */\n show(column: number, row: number): string;\n}\n\n/** This function connects the pointer and the arrow keys of a chart to its cursor. */\nfunction connect(svg: SVGElement, cursor: Cursor, tell: (text: string) => void): void {\n let column = -1;\n let row = 0;\n const move = (nextColumn: number, nextRow: number): void => {\n column = Math.max(0, Math.min(cursor.columns - 1, nextColumn));\n row = Math.max(0, Math.min(cursor.rows - 1, nextRow));\n tell(cursor.show(column, row));\n };\n svg.addEventListener(\"pointermove\", (event) => {\n const box = svg.getBoundingClientRect();\n const [c, r] = cursor.at((event as PointerEvent).clientX - box.left, (event as PointerEvent).clientY - box.top);\n move(c, r);\n });\n svg.addEventListener(\"keydown\", (event) => {\n const steps: Readonly<Record<string, readonly [number, number]>> = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] };\n const step = steps[(event as KeyboardEvent).key];\n if (step === undefined) return;\n event.preventDefault();\n move(column < 0 ? 0 : column + step[0], row + step[1]);\n });\n}\n\n/** This function makes the frame of a chart with its text for a screen reader. */\nfunction chartFrame(plot: Plot, label: string): SVGElement {\n return s(\"svg\", { class: \"rx-svg\", width: plot.width, height: plot.height, viewBox: `0 0 ${plot.width} ${plot.height}`, role: \"img\", \"aria-label\": label, tabindex: 0 });\n}\n\n/** This function draws a band with one strength for each place along the axis. */\nfunction fadedBand(plot: Plot, panel: CurvePanel, scale: ValueScale, axis: AxisSpec, id: string): SVGElement[] {\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const curve = panel.slice.curve;\n const px = (at: ResponseValue): number => plot.left + placeOn(axis, at) * length;\n const py = (value: number): number => plot.bottom - valuePlace(scale, value) * height;\n const stops = curve.map((place) => s(\"stop\", { class: \"rx-band-stop\", offset: placeOn(axis, place.at), \"stop-opacity\": fadeOf(place.nearest).toFixed(3) }));\n const gradient = s(\"linearGradient\", { id, gradientUnits: \"userSpaceOnUse\", x1: plot.left, x2: plot.right, y1: 0, y2: 0 }, ...stops);\n const upper = curve.map((place): Pixel => [px(place.at), py(place.high)]);\n const lower = curve.map((place): Pixel => [px(place.at), py(place.low)]);\n return [s(\"defs\", {}, gradient), s(\"path\", { class: \"rx-band\", d: bandPath(upper, lower), fill: `url(#${id})` })];\n}\n\n/** This function draws a band and a mark at each level of a level axis. */\nfunction levelMarks(plot: Plot, panel: CurvePanel, scale: ValueScale, axis: AxisSpec): SVGElement[] {\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const room = Math.min(44, (length / Math.max(1, axis.levels.length)) * 0.5);\n return panel.slice.curve.flatMap((place) => {\n const x = plot.left + placeOn(axis, place.at) * length;\n const top = plot.bottom - valuePlace(scale, place.high) * height;\n const bottom = plot.bottom - valuePlace(scale, place.low) * height;\n const y = plot.bottom - valuePlace(scale, place.value) * height;\n return [\n s(\"rect\", { class: \"rx-whisker\", x: x - room / 2, y: top, width: room, height: Math.max(1, bottom - top), rx: 4, \"fill-opacity\": (0.3 * fadeOf(place.nearest)).toFixed(3) }),\n s(\"line\", { class: \"rx-line\", x1: x - room / 2, x2: x + room / 2, y1: y, y2: y }),\n ];\n });\n}\n\n/** This function draws a chart with a fitted curve, its band and the measured points. */\nfunction curveChart(view: ExplorerView, panel: CurvePanel, width: number, id: string, tell: (text: string) => void): SVGElement {\n const plot = plotOf(width, 270, view);\n const scale: ValueScale = { range: valueRange(view), log: view.log };\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const curve = panel.slice.curve;\n const px = (at: ResponseValue): number => plot.left + placeOn(view.x, at) * length;\n const py = (value: number): number => plot.bottom - valuePlace(scale, value) * height;\n const smooth = view.x.kind === \"number\";\n const marks = smooth\n ? [...fadedBand(plot, panel, scale, view.x, id), s(\"path\", { class: \"rx-line\", d: linePath(curve.map((place): Pixel => [px(place.at), py(place.value)])) })]\n : levelMarks(plot, panel, scale, view.x);\n const room = smooth ? 0 : Math.min(30, (length / Math.max(1, view.x.levels.length)) * 0.35);\n const dots = panel.slice.points.map((point) => s(\"circle\", { class: \"rx-dot\", cx: px(point.at) + jitter(point.id, room), cy: py(point.value), r: 3.5 }));\n const ticks = numberTicks(scale.range[0], scale.range[1], scale.log, Math.max(2, Math.floor(height / 50)));\n const rule = s(\"line\", { class: \"rx-cursor\", x1: 0, x2: 0, y1: plot.top, y2: plot.bottom, visibility: \"hidden\" });\n const ring = s(\"circle\", { class: \"rx-ring\", cx: 0, cy: 0, r: 5, visibility: \"hidden\" });\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label} over ${view.x.label}.`.trim());\n svg.append(valueAxis(plot, ticks), ...marks, ...dots, xAxis(plot, view.x), rule, ring);\n connect(\n svg,\n {\n columns: curve.length,\n rows: 1,\n at: (x) => {\n const distance = (place: (typeof curve)[number]): number => Math.abs(px(place.at) - x);\n const nearest = curve.reduce((best, place) => (distance(place) < distance(best) ? place : best));\n return [curve.indexOf(nearest), 0];\n },\n show: (column) => {\n const place = curve[column] as (typeof curve)[number];\n for (const [name, value] of [[\"x1\", px(place.at)], [\"x2\", px(place.at)]] as const) rule.setAttribute(name, String(value));\n ring.setAttribute(\"cx\", String(px(place.at)));\n ring.setAttribute(\"cy\", String(py(place.value)));\n rule.setAttribute(\"visibility\", \"visible\");\n ring.setAttribute(\"visibility\", \"visible\");\n return curveText(view.x, place);\n },\n },\n tell,\n );\n return svg;\n}\n\n/** This function draws a chart of a surface, or the separate cells of a table. */\nfunction surfaceChart(view: ExplorerView, panel: SurfacePanel, width: number, tell: (text: string) => void): SVGElement {\n const axisY = view.y as AxisSpec;\n const plot = plotOf(width, Math.min(380, Math.max(280, width * 0.72)), view);\n const { x, y, cells } = panel.surface;\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const xEdges = cellEdges(x.map((value) => placeOn(view.x, value)));\n const yEdges = cellEdges(y.map((value) => placeOn(axisY, value)));\n const range = heatRange(view);\n const gap = panel.cells ? 2 : 0;\n const cellMarks = cells.flatMap((row, j) =>\n row.flatMap((band, i) => {\n const left = plot.left + (xEdges[i] as number) * length;\n const right = plot.left + (xEdges[i + 1] as number) * length;\n const lower = plot.bottom - (yEdges[j] as number) * height;\n const upper = plot.bottom - (yEdges[j + 1] as number) * height;\n const box = { x: left + gap / 2, y: upper + gap / 2, width: Math.max(0.5, right - left - gap + (gap === 0 ? 0.6 : 0)), height: Math.max(0.5, lower - upper - gap + (gap === 0 ? 0.6 : 0)) };\n const step = heatStep(band.value, range, view.log);\n const parts = [s(\"rect\", { ...box, class: `rx-h${step}` })];\n const veil = veilOf(band.nearest);\n if (veil > 0.02) parts.push(s(\"rect\", { ...box, class: \"rx-veil\", \"fill-opacity\": veil.toFixed(3) }));\n if (panel.cells && box.width > 34 && box.height > 18) parts.push(s(\"text\", { class: `rx-cell-text ${step > HEAT_STEPS / 2 ? \"rx-on-dark\" : \"rx-on-light\"}`, x: box.x + box.width / 2, y: box.y + box.height / 2 + 4, \"text-anchor\": \"middle\" }, formatValue(band.value)));\n return parts;\n }),\n );\n const dots = panel.surface.points.map((point) =>\n s(\"circle\", { class: \"rx-dot rx-dot-heat\", cx: plot.left + placeOn(view.x, point.at[0]) * length + jitter(point.id, 6), cy: plot.bottom - placeOn(axisY, point.at[1]) * height + jitter(`${point.id}y`, 6), r: 2.5 }),\n );\n const outline = s(\"rect\", { class: \"rx-cell-cursor\", x: 0, y: 0, width: 0, height: 0, visibility: \"hidden\" });\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label} over ${view.x.label} and ${axisY.label}.`.trim());\n svg.append(...cellMarks, ...dots, surfaceAxis(plot, axisY), xAxis(plot, view.x), outline);\n const find = (edges: readonly number[], share: number): number => {\n const index = edges.findIndex((edge) => edge > share);\n return Math.max(0, (index < 0 ? edges.length : index) - 1);\n };\n connect(\n svg,\n {\n columns: x.length,\n rows: y.length,\n at: (px, py) => [find(xEdges, (px - plot.left) / length), y.length - 1 - find(yEdges, (plot.bottom - py) / height)],\n show: (column, row) => {\n const j = y.length - 1 - row;\n outline.setAttribute(\"x\", String(plot.left + (xEdges[column] as number) * length));\n outline.setAttribute(\"width\", String(((xEdges[column + 1] as number) - (xEdges[column] as number)) * length));\n outline.setAttribute(\"y\", String(plot.bottom - (yEdges[j + 1] as number) * height));\n outline.setAttribute(\"height\", String(((yEdges[j + 1] as number) - (yEdges[j] as number)) * height));\n outline.setAttribute(\"visibility\", \"visible\");\n return cellText(view.x, axisY, x[column] as ResponseValue, y[j] as ResponseValue, cells[j]?.[column] as (typeof cells)[number][number]);\n },\n },\n tell,\n );\n return svg;\n}\n\n/** This function draws the measured points of a measure with no model. */\nfunction pointsChart(view: ExplorerView, panel: PointsPanel, width: number): SVGElement {\n const plot = plotOf(width, 270, view);\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label}: ${panel.points.length} measured points.`.trim());\n if (view.y === null) {\n const scale: ValueScale = { range: valueRange(view), log: view.log };\n const room = view.x.kind === \"levels\" ? Math.min(30, (length / Math.max(1, view.x.levels.length)) * 0.35) : 0;\n const dots = panel.points.map((point) => s(\"circle\", { class: \"rx-dot\", cx: plot.left + placeOn(view.x, point.at[0] as ResponseValue) * length + jitter(point.id, room), cy: plot.bottom - valuePlace(scale, point.value) * height, r: 3.5 }));\n const ticks = numberTicks(scale.range[0], scale.range[1], scale.log, Math.max(2, Math.floor(height / 50)));\n svg.append(valueAxis(plot, ticks), ...dots, xAxis(plot, view.x));\n return svg;\n }\n const axisY = view.y;\n const range = heatRange(view);\n const dots = panel.points.map((point) =>\n s(\"circle\", { class: `rx-h${heatStep(point.value, range, view.log)} rx-ring-dot`, cx: plot.left + placeOn(view.x, point.at[0] as ResponseValue) * length + jitter(point.id, 8), cy: plot.bottom - placeOn(axisY, point.at[1] as ResponseValue) * height + jitter(`${point.id}y`, 8), r: 5 }),\n );\n svg.append(...dots, surfaceAxis(plot, axisY), xAxis(plot, view.x));\n return svg;\n}\n\n/** This function gives the number of measured points of a panel. */\nfunction pointCount(panel: ExplorerPanel): number {\n if (panel.kind === \"curve\") return panel.slice.points.length;\n return panel.kind === \"surface\" ? panel.surface.points.length : panel.points.length;\n}\n\n/** This function gives the sentence about the measured points of a panel. */\nfunction pointsText(panel: ExplorerPanel): string {\n const count = pointCount(panel);\n if (count === 0) return \"No measured point has these held values.\";\n return count === 1 ? \"1 measured point has these held values.\" : `${count} measured points have these held values.`;\n}\n\n/** This function draws one panel. */\nfunction panelChart(view: ExplorerView, panel: ExplorerPanel, width: number, id: string, tell: (text: string) => void): SVGElement {\n if (panel.kind === \"curve\") return curveChart(view, panel, width, id, tell);\n return panel.kind === \"surface\" ? surfaceChart(view, panel, width, tell) : pointsChart(view, panel, width);\n}\n\n/** This function makes the legend of a view. */\nfunction legendOf(view: ExplorerView): HTMLElement {\n const item = (mark: HTMLElement, text: string): HTMLElement => h(\"span\", { class: \"rx-key\" }, mark, text);\n const mark = (name: string): HTMLElement => h(\"i\", { class: `rx-mark ${name}`, \"aria-hidden\": \"true\" });\n const parts: Child[] = [];\n const panel = view.panels[0];\n const surface = view.y !== null && panel?.kind !== \"curve\";\n if (panel?.kind === \"curve\") parts.push(item(mark(\"rx-mark-line\"), \"fitted value\"), item(mark(\"rx-mark-band\"), \"band: one held-out error each side. It fades away from the data.\"));\n if (surface) {\n const [low, high] = heatRange(view);\n const ramp = h(\"i\", { class: \"rx-ramp\", \"aria-hidden\": \"true\" }, ...Array.from({ length: HEAT_STEPS }, (_, i) => h(\"b\", { class: `rx-s${i}` })));\n parts.push(h(\"span\", { class: \"rx-key\" }, formatValue(low), ramp, formatValue(high)));\n if (panel?.kind === \"surface\") parts.push(item(mark(\"rx-mark-veil\"), \"gray veil: far from the data\"));\n }\n if (panel !== undefined) parts.push(item(mark(\"rx-mark-dot\"), \"measured point\"));\n return h(\"p\", { class: \"rx-legend\" }, ...parts);\n}\n\n/** This function makes a table of numbers. */\nfunction tableOf(view: ExplorerView, panel: ExplorerPanel): HTMLElement {\n const { columns, rows } = numberTable(view, panel);\n const head = h(\"tr\", {}, ...columns.map((column) => h(\"th\", { scope: \"col\" }, column)));\n const body = rows.map((row) => h(\"tr\", {}, ...row.map((cell) => h(\"td\", {}, cell))));\n const table = h(\"table\", { class: \"rx-table\" }, ...(panel.title === \"\" ? [] : [h(\"caption\", {}, panel.title)]), h(\"thead\", {}, head), h(\"tbody\", {}, ...body));\n return table;\n}\n\n/** This function makes a select of dimensions. The first option is the value `none`, if the control has one. */\nfunction dimensionSelect(label: string, key: string, choices: readonly DimensionChoice[], value: string | null, none: string | null, change: (id: string | null) => void): HTMLElement {\n const options = choices.map((choice) => {\n const text = choice.disabled ? `${choice.label}: ${choice.reason}` : choice.label;\n return h(\"option\", { value: choice.id, disabled: choice.disabled, selected: choice.id === value }, text);\n });\n const select = h(\"select\", { \"data-key\": key }, ...(none === null ? [] : [h(\"option\", { value: \"\", selected: value === null }, none)]), ...options);\n select.addEventListener(\"change\", () => change(select.value === \"\" ? null : select.value));\n return h(\"label\", { class: \"rx-field\" }, h(\"span\", {}, label), select);\n}\n\n/** The fields of a level in a group. */\ninterface LevelOption {\n readonly text: string;\n readonly checked: boolean;\n readonly disabled: boolean;\n readonly reason: string;\n readonly choose: () => void;\n}\n\n/** This function makes a select of levels. A closed select shows the held value and takes one row. */\nfunction levelSelect(label: string, key: string, options: readonly LevelOption[], note: string): HTMLElement {\n const items = options.map((option, i) => {\n const text = option.disabled ? `${option.text}: ${option.reason}` : option.text;\n return h(\"option\", { value: i, disabled: option.disabled, selected: option.checked }, text);\n });\n const select = h(\"select\", { \"data-key\": key }, ...items);\n select.addEventListener(\"change\", () => options[Number(select.value)]?.choose());\n const field = h(\"label\", { class: \"rx-field\" }, h(\"span\", {}, label), select);\n return h(\"div\", { class: \"rx-hold\" }, field, note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, note));\n}\n\n/** This function makes a group of levels. Level buttons are radio inputs, so the keyboard works with no script. */\nfunction levelGroup(label: string, key: string, name: string, options: readonly LevelOption[], note: string): HTMLElement {\n if (levelForm(options.length) === \"select\") return levelSelect(label, key, options, note);\n const chips = options.map((option, i) => {\n const input = h(\"input\", { class: \"rx-radio\", type: \"radio\", name, checked: option.checked, disabled: option.disabled, \"data-key\": `${key}:${i}` });\n input.addEventListener(\"change\", option.choose);\n return h(\"label\", { class: \"rx-chip\", title: option.reason === \"\" ? undefined : option.reason }, input, h(\"span\", {}, option.text));\n });\n const legend = h(\"legend\", { class: \"rx-name\" }, label);\n return h(\"fieldset\", { class: \"rx-hold\" }, legend, h(\"div\", { class: \"rx-chips\" }, ...chips), note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, note));\n}\n\n/** This function makes a slider over the values of a held dimension. */\nfunction stopSlider(control: HoldControl, key: string, change: (value: ResponseValue) => void): HTMLElement {\n const values = control.options.map((option) => option.value);\n const index = Math.max(0, values.indexOf(control.value));\n const output = h(\"output\", { class: \"rx-value\" }, formatValue(control.value));\n const input = h(\"input\", { class: \"rx-slider\", type: \"range\", min: 0, max: values.length - 1, step: 1, value: index, disabled: !control.applies, \"data-key\": key, \"aria-label\": control.label, \"aria-valuetext\": formatValue(control.value) });\n input.addEventListener(\"input\", () => {\n const value = values[Number(input.value)] as ResponseValue;\n output.textContent = formatValue(value);\n input.setAttribute(\"aria-valuetext\", formatValue(value));\n change(value);\n });\n const head = h(\"div\", { class: \"rx-slider-head\" }, h(\"span\", { class: \"rx-name\" }, control.label), output);\n return h(\"div\", { class: \"rx-hold\" }, head, input, control.note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, control.note));\n}\n\n/** This function shows each fault of a bad record, with its path. */\nfunction faultView(faults: readonly { readonly path: string; readonly message: string }[]): HTMLElement {\n const items = faults.slice(0, MAX_FAULTS).map((fault) => h(\"li\", {}, h(\"code\", {}, fault.path === \"\" ? \"(the record)\" : fault.path), ` ${fault.message}`));\n const more = faults.length > MAX_FAULTS ? h(\"p\", {}, `The list shows ${MAX_FAULTS} of ${faults.length} faults.`) : null;\n const title = faults.length === 1 ? \"This record has 1 fault.\" : `This record has ${faults.length} faults.`;\n return h(\"div\", { class: \"rx-faults\", role: \"alert\" }, h(\"p\", { class: \"rx-faults-title\" }, title), h(\"ul\", {}, ...items), more);\n}\n\n/**\n * This function shows a record of the format `response-records/1` in a host element. It reads the record only with\n * `parseResponseRecord`. A bad record shows its faults with their paths, and the function does not throw.\n *\n * @param host - The element of the explorer. The function replaces its children.\n * @param recordJson - The record as JSON text, or as parsed data.\n * @param options - The first state, the time of a surface and the clock.\n */\nexport function mountExplorer(host: HTMLElement, recordJson: unknown, options: ExplorerOptions = {}): ExplorerHandle {\n const parsed = openRecord(recordJson);\n if (!parsed.ok) {\n host.replaceChildren(h(\"div\", { class: \"response-explorer\" }, faultView(parsed.faults)));\n return { state: () => null, destroy: () => host.replaceChildren() };\n }\n return mountRecord(host, parsed.record, options);\n}\n\n/** This function connects a good record to the DOM. */\nfunction mountRecord(host: HTMLElement, record: ResponseRecord, options: ExplorerOptions): ExplorerHandle {\n const { budgetMs = SURFACE_BUDGET_MS, now = (): number => performance.now() } = options;\n const mount = ++mounts;\n let state = settle(record, options.initial);\n let cap = MAX_STEPS;\n let frame = 0;\n let drawnWidth = 0;\n let view: ExplorerView | undefined;\n\n const controls = h(\"div\", { class: \"rx-controls\" });\n const panels = h(\"div\", { class: \"rx-panels\" });\n const error = h(\"p\", { class: \"rx-error\" });\n const model = h(\"p\", { class: \"rx-note\" });\n const legend = h(\"div\", { class: \"rx-legend-box\" });\n const readout = h(\"p\", { class: \"rx-readout\", \"aria-live\": \"polite\" });\n const numbers = h(\"div\", { class: \"rx-numbers-body\" });\n const details = h(\"details\", { class: \"rx-numbers\" }, h(\"summary\", {}, \"Show the numbers\"), numbers);\n const chart = h(\"div\", { class: \"rx-chart\" }, error, panels, legend, readout, model, details);\n const root = h(\"div\", { class: \"response-explorer\" }, controls, chart);\n\n const tell = (text: string): void => {\n readout.textContent = text;\n };\n\n /** This function fills the table when the visitor opens it, so a closed table costs no time. */\n const drawNumbers = (): void => {\n numbers.replaceChildren(...(details.open && view !== undefined ? view.panels.map((panel) => h(\"div\", { class: \"rx-table-box scroll-cue\" }, tableOf(view as ExplorerView, panel))) : []));\n };\n\n /** This function draws the charts of the last view at the width of the host. */\n const drawCharts = (): void => {\n const current = view;\n if (current === undefined) return;\n const single = current.panels.length === 1;\n const available = panels.clientWidth > 0 ? panels.clientWidth : FALLBACK_WIDTH;\n const columns = single ? 1 : Math.min(current.panels.length, Math.max(1, Math.floor((available + 12) / 272)));\n const width = Math.floor((available - (columns - 1) * 12) / columns);\n drawnWidth = available;\n panels.replaceChildren(\n ...current.panels.map((panel, i) => {\n const title = panel.title === \"\" ? null : h(\"figcaption\", { class: \"rx-panel-title\" }, panel.title);\n const chartBox = panelChart(current, panel, width, `rx-band-${mount}-${i}`, tell);\n return h(\"figure\", { class: \"rx-panel\" }, title, chartBox, h(\"p\", { class: \"rx-note\" }, pointsText(panel)));\n }),\n );\n };\n\n /** This function asks the core for a view, and it draws the view. */\n const drawView = (): void => {\n const next = viewOf(record, state, { stepsCap: cap, budgetMs, now });\n view = next;\n cap = next.nextCap;\n if (next.problem !== \"\") {\n error.textContent = `The record refused this view: ${next.problem}`;\n } else {\n const head = next.error === null ? null : h(\"strong\", {}, \"Held-out error. \");\n error.replaceChildren(...(head === null ? [] : [head]), next.errorText);\n }\n model.textContent = [next.modelText, next.gridText, next.rangeText].filter((text) => text !== \"\").join(\" \");\n legend.replaceChildren(legendOf(next));\n tell(\"Move over a chart, or focus it and use the arrow keys.\");\n drawCharts();\n drawNumbers();\n };\n\n /** This function draws at the next frame. A slider gives many events in one frame. */\n const later = (): void => {\n if (frame !== 0) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n drawView();\n });\n };\n\n /** This function makes the controls of the state again, and it keeps the focus on the same control. */\n const drawControls = (): void => {\n const focused = document.activeElement instanceof HTMLElement ? document.activeElement.dataset[\"key\"] : undefined;\n const update = (next: ExplorerState): void => {\n state = next;\n drawControls();\n drawView();\n };\n const measures = levelGroup(\n \"Measure\",\n \"measure\",\n `rx-measure-${mount}`,\n record.measures.map((m) => ({ text: m.label, checked: m.id === state.measure, disabled: false, reason: \"\", choose: () => update(setMeasure(record, state, m.id)) })),\n \"\",\n );\n const axes = h(\n \"div\",\n { class: \"rx-axes\" },\n dimensionSelect(\"Across\", \"x\", axisChoices(record, state, \"x\"), state.x, null, (id) => update(setAxis(record, state, \"x\", id))),\n dimensionSelect(\"Up\", \"y\", axisChoices(record, state, \"y\"), state.y, \"None (a curve)\", (id) => update(setAxis(record, state, \"y\", id))),\n dimensionSelect(\"Panels\", \"facet\", facetChoices(record, state), state.facet, \"One panel\", (id) => update(setFacet(record, state, id))),\n );\n const holds = holdControls(record, state).map((control) => {\n if (control.kind === \"stops\") {\n return stopSlider(control, `hold:${control.id}`, (value) => {\n state = setHold(record, state, control.id, value);\n later();\n });\n }\n const levels = control.options.map((option) => ({ text: option.text, checked: option.value === control.value, disabled: option.disabled, reason: option.reason, choose: () => update(setHold(record, state, control.id, option.value)) }));\n return levelGroup(control.label, `hold:${control.id}`, `rx-${mount}-${control.id}`, levels, control.note);\n });\n const held = holds.length === 0 ? [] : [h(\"p\", { class: \"rx-section\" }, \"Held values\"), ...holds];\n controls.replaceChildren(measures, axes, ...held);\n if (focused !== undefined) {\n const keyed = [...controls.querySelectorAll<HTMLElement>(\"[data-key]\")].find((el) => el.dataset[\"key\"] === focused);\n keyed?.focus();\n }\n };\n\n details.addEventListener(\"toggle\", drawNumbers);\n host.replaceChildren(root);\n drawControls();\n drawView();\n\n const observer =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n if (panels.clientWidth > 0 && Math.abs(panels.clientWidth - drawnWidth) > 1) drawCharts();\n });\n observer?.observe(panels);\n\n return {\n state: () => state,\n destroy: () => {\n observer?.disconnect();\n if (frame !== 0) cancelAnimationFrame(frame);\n host.replaceChildren();\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/explorer/model.ts","../../src/explorer/view.ts"],"sourcesContent":["/**\n * The pure core of the response explorer: the state, the rules of the controls and the data of a view. This module\n * reads a record of the format `response-records/1` only with `@mark1russell7/rigor-statistics`. It has no DOM and no\n * clock of its own, so a test gives it each input.\n *\n * The rules of the controls follow the rules of a conditional dimension. The functions `axisChoices`, `facetChoices`\n * and `holdControls` offer only combinations that `sliceResponse` and `surfaceResponse` accept. The function `settle`\n * gives the nearest good state for any wanted state.\n */\n\nimport {\n heldOutError,\n parseResponseRecord,\n quantile,\n responseCells,\n sliceResponse,\n surfaceResponse,\n whenHolds,\n type ParsedResponseRecord,\n type ResponseBand,\n type ResponseCurvePoint,\n type ResponseDimension,\n type ResponseHeldOutError,\n type ResponseInputValue,\n type ResponseMeasure,\n type ResponseModel,\n type ResponsePoint,\n type ResponseRecord,\n type ResponseSlice,\n type ResponseSurface,\n type ResponseValue,\n} from \"@mark1russell7/rigor-statistics\";\n\n/** The largest number of values on a continuous axis. It is the default of `ResponseViewOptions.steps`. */\nexport const MAX_STEPS = 33;\n/** The smallest number of values on a continuous axis. A smaller grid shows too little of the response. */\nexport const MIN_STEPS = 5;\n/**\n * The largest number of point reads of one view. The field `nearest` of each place reads each point, so the cost of a\n * view is its number of places times the number of points. This number is a first bound, not a measured time.\n * `SURFACE_BUDGET_MS` corrects the grid when a surface takes too long on the device.\n */\nexport const READ_BUDGET = 400_000;\n/** The time of one surface in milliseconds. A longer surface gives a smaller grid for the next surface. */\nexport const SURFACE_BUDGET_MS = 50;\n/** The largest number of panels of one view. */\nexport const MAX_PANELS = 8;\n/** The largest number of stops of a held continuous dimension. */\nexport const MAX_STOPS = 33;\n/** The most levels that a row of buttons shows. A longer group is a select, so it does not push the chart down the page. */\nexport const MAX_CHIPS = 8;\n/** The distance from a measurement, from 0 to 1, at which a band has its weakest color. */\nexport const FADE_END = 0.5;\n/** The number of steps of the color scale of a surface. The CSS classes `rx-h0` to `rx-h8` give the colors. */\nexport const HEAT_STEPS = 9;\n\n/** The choices of a visitor. */\nexport interface ExplorerState {\n /** The id of the measure. */\n readonly measure: string;\n /** The id of the dimension of the horizontal axis. */\n readonly x: string;\n /** The id of the dimension of the vertical axis of a surface. The value `null` gives a curve. */\n readonly y: string | null;\n /** The id of the dimension with one panel for each of its values. The value `null` gives one panel. */\n readonly facet: string | null;\n /** The held value of each dimension. A dimension on an axis keeps its value for a later view. */\n readonly hold: Readonly<Record<string, ResponseValue>>;\n}\n\n/** The two axes of a view. */\nexport type AxisSlot = \"x\" | \"y\";\n\n/** A dimension that a control offers. */\nexport interface DimensionChoice {\n readonly id: string;\n readonly label: string;\n readonly disabled: boolean;\n /** The reason of a disabled choice. A good choice has an empty string. */\n readonly reason: string;\n}\n\n/** A value that a hold control offers. */\nexport interface HoldOption {\n readonly value: ResponseValue;\n readonly text: string;\n readonly disabled: boolean;\n readonly reason: string;\n}\n\n/** The control of one held dimension. */\nexport interface HoldControl {\n readonly id: string;\n readonly label: string;\n /** The value `levels` gives one button for each level. The value `stops` gives a slider over the measured values. */\n readonly kind: \"levels\" | \"stops\";\n /** The value `false` means that the dimension has no value at the held level of its parent. */\n readonly applies: boolean;\n /** The condition of the dimension, as text. A dimension with no condition has an empty string. */\n readonly note: string;\n readonly options: readonly HoldOption[];\n readonly value: ResponseValue;\n}\n\n/** One axis of a chart. A number axis has a linear or log place. A level axis has one equal band for each level. */\nexport interface AxisSpec {\n readonly id: string;\n readonly label: string;\n readonly kind: \"number\" | \"levels\";\n readonly log: boolean;\n /** The two ends of a number axis. */\n readonly range: readonly [number, number];\n /** The levels of a level axis. */\n readonly levels: readonly ResponseValue[];\n}\n\n/** The fields of each kind of panel. */\ninterface PanelBase {\n /** The name of the panel in a view with panels. The only panel of a view has an empty string. */\n readonly title: string;\n /** The value of the facet dimension in this panel. */\n readonly level: ResponseValue | null;\n}\n\n/** A fitted curve with its band and the measured points. */\nexport interface CurvePanel extends PanelBase {\n readonly kind: \"curve\";\n readonly slice: ResponseSlice;\n}\n\n/** A fitted surface. With `cells`, the view shows separate cells with their values, not a smooth surface. */\nexport interface SurfacePanel extends PanelBase {\n readonly kind: \"surface\";\n readonly cells: boolean;\n readonly surface: ResponseSurface;\n}\n\n/** A measured point of a panel with no model. */\nexport interface PlainPoint {\n readonly id: string;\n /** The value of each varied dimension. */\n readonly at: readonly ResponseValue[];\n readonly value: number;\n}\n\n/** The measured points of a measure with no model. */\nexport interface PointsPanel extends PanelBase {\n readonly kind: \"points\";\n readonly points: readonly PlainPoint[];\n}\n\n/** One panel of a view. */\nexport type ExplorerPanel = CurvePanel | SurfacePanel | PointsPanel;\n\n/** The data of one view. */\nexport interface ExplorerView {\n readonly measure: ResponseMeasure;\n readonly x: AxisSpec;\n readonly y: AxisSpec | null;\n readonly panels: readonly ExplorerPanel[];\n /** The value `true` gives a log value axis. */\n readonly log: boolean;\n /** The held-out error. A measure with no model has none. */\n readonly error: ResponseHeldOutError | null;\n /** The held-out error in plain words. */\n readonly errorText: string;\n /** The kind of the model in plain words. */\n readonly modelText: string;\n /** The size of the grid of a surface in plain words. A curve has an empty string. */\n readonly gridText: string;\n /** The places that the range of the measure moved, in plain words. With no such place, this is an empty string. */\n readonly rangeText: string;\n /** The text of a request that the record refused. A good view has an empty string. */\n readonly problem: string;\n /** The number of values on a continuous axis of this view. */\n readonly steps: number;\n /** The time of this view in milliseconds. */\n readonly elapsedMs: number;\n /** The largest number of steps of the next view. */\n readonly nextCap: number;\n}\n\n/** The inputs of `viewOf`. */\nexport interface ViewOptions {\n /** The largest number of steps. The value of `nextCap` of the last view goes here. */\n readonly stepsCap?: number;\n /** The time of a surface in milliseconds. The default is `SURFACE_BUDGET_MS`. */\n readonly budgetMs?: number;\n /** The clock in milliseconds. The default gives 0, so a view with no clock does not drop its grid. */\n readonly now?: () => number;\n}\n\n/** A rectangle of a table of numbers. */\nexport interface NumberTable {\n readonly columns: readonly string[];\n readonly rows: readonly (readonly string[])[];\n}\n\n/** One tick of an axis. */\nexport interface Tick {\n /** The place on the axis, from 0 to 1. */\n readonly place: number;\n readonly text: string;\n}\n\n/**\n * This function reads a record from JSON text or from parsed data. It does not throw: bad data gives faults with\n * their paths.\n */\nexport function openRecord(value: unknown): ParsedResponseRecord {\n if (typeof value !== \"string\") return parseResponseRecord(value);\n try {\n return parseResponseRecord(JSON.parse(value));\n } catch (error) {\n return { ok: false, faults: [{ path: \"\", message: `this text is not JSON: ${String(error)}.` }] };\n }\n}\n\nconst numberText = new Intl.NumberFormat(\"en-US\", { maximumSignificantDigits: 3 });\n\n/** This function gives the text of a value: a number with three significant digits, or the text of a level. */\nexport function formatValue(value: ResponseInputValue): string {\n if (value === null) return \"none\";\n return typeof value === \"number\" ? numberText.format(value) : value;\n}\n\n/** This function gives the dimension with an id that the state or the record names. */\nfunction dimensionOf(record: ResponseRecord, id: string): ResponseDimension {\n const dimension = record.dimensions.find((d) => d.id === id);\n if (dimension === undefined) throw new RangeError(`The record has no dimension \"${id}\".`);\n return dimension;\n}\n\n/** This function gives the measured values of a dimension, with no `null`. */\nfunction measuredValues(record: ResponseRecord, id: string): ResponseValue[] {\n return record.points.flatMap((p) => {\n const value = p.values[id];\n return value === null || value === undefined ? [] : [value];\n });\n}\n\nconst stopCache = new WeakMap<ResponseRecord, Map<string, readonly ResponseValue[]>>();\n\n/** This function gives the distinct measured values of a continuous dimension, in order. */\nfunction distinctNumbers(record: ResponseRecord, id: string): number[] {\n const numbers = measuredValues(record, id).filter((v) => typeof v === \"number\");\n return [...new Set(numbers)].sort((a, b) => a - b);\n}\n\n/**\n * This function gives the values that a visitor can hold: each level, or the measured values of a continuous dimension.\n * With more than `MAX_STOPS` measured values, it gives that number of quantiles of them.\n */\nexport function stopsOf(record: ResponseRecord, dimension: ResponseDimension): readonly ResponseValue[] {\n if (dimension.kind !== \"continuous\") return dimension.levels;\n let stops = stopCache.get(record);\n if (stops === undefined) stopCache.set(record, (stops = new Map()));\n const known = stops.get(dimension.id);\n if (known !== undefined) return known;\n const distinct = distinctNumbers(record, dimension.id);\n const thin = (): number[] => [...new Set(Array.from({ length: MAX_STOPS }, (_, i) => quantile(distinct, i / (MAX_STOPS - 1), \"nearest-rank\")))];\n const found = distinct.length === 0 ? [dimension.range[0]] : distinct.length > MAX_STOPS ? thin() : distinct;\n stops.set(dimension.id, found);\n return found;\n}\n\n/** This function gives the place of a number on a continuous dimension, from 0 to 1. */\nfunction shareOf(dimension: ResponseDimension & { kind: \"continuous\" }, value: number): number {\n const scale = (v: number): number => (dimension.log === true ? Math.log10(v) : v);\n const [low, high] = dimension.range;\n return (scale(value) - scale(low)) / (scale(high) - scale(low));\n}\n\n/**\n * This function gives the option `tolerance` of a view. A dimension with all its measured values as stops needs none.\n * A thinned dimension needs half of its largest gap, so each measured point matches a stop.\n */\nexport function toleranceOf(record: ResponseRecord): number {\n let tolerance = 0;\n for (const dimension of record.dimensions) {\n if (dimension.kind !== \"continuous\") continue;\n const stops = stopsOf(record, dimension) as readonly number[];\n if (stops.length === distinctNumbers(record, dimension.id).length) continue;\n for (let i = 1; i < stops.length; i++) {\n const gap = shareOf(dimension, stops[i] as number) - shareOf(dimension, stops[i - 1] as number);\n tolerance = Math.max(tolerance, gap / 2);\n }\n }\n return tolerance;\n}\n\n/** This function gives the usual value of a dimension: the measured median, or the most common level in `among`. */\nfunction usualValue(record: ResponseRecord, dimension: ResponseDimension, among?: readonly ResponseValue[]): ResponseValue {\n const values = measuredValues(record, dimension.id);\n if (dimension.kind === \"continuous\") {\n const numbers = values.filter((v) => typeof v === \"number\");\n return numbers.length === 0 ? dimension.range[0] : quantile(numbers, 0.5, \"nearest-rank\");\n }\n const levels: readonly ResponseValue[] = among ?? dimension.levels;\n const count = (level: ResponseValue): number => values.filter((v) => v === level).length;\n return levels.reduce((best, level) => (count(level) > count(best) ? level : best), levels[0] as ResponseValue);\n}\n\n/** This function gives the stop of a dimension that is nearest to a value, or `undefined` for a value of no use. */\nfunction nearestStop(record: ResponseRecord, dimension: ResponseDimension, value: ResponseValue | undefined): ResponseValue | undefined {\n const stops = stopsOf(record, dimension);\n if (value === undefined) return undefined;\n if (dimension.kind !== \"continuous\") return stops.includes(value) ? value : undefined;\n if (typeof value !== \"number\") return undefined;\n const far = (stop: ResponseValue): number => Math.abs(shareOf(dimension, stop as number) - shareOf(dimension, value));\n return stops.reduce((best, stop) => (far(stop) < far(best) ? stop : best));\n}\n\n/** This function gives the levels that the parent of each varied conditional dimension needs. */\nfunction neededLevels(record: ResponseRecord, varied: readonly string[]): Map<string, readonly ResponseValue[]> {\n const needed = new Map<string, readonly ResponseValue[]>();\n for (const id of varied) {\n const when = dimensionOf(record, id).when;\n if (when === undefined) continue;\n const earlier = needed.get(when.dimension);\n needed.set(when.dimension, earlier === undefined ? when.levels : earlier.filter((level) => when.levels.includes(level)));\n }\n return needed;\n}\n\n/** This function gives the condition of a dimension as a phrase of a sentence. */\nfunction whenText(record: ResponseRecord, dimension: ResponseDimension): string {\n const when = dimension.when;\n if (when === undefined) return \"\";\n return `only when ${dimensionOf(record, when.dimension).label} is ${when.levels.map(formatValue).join(\" or \")}`;\n}\n\nconst variedOf = (state: Pick<ExplorerState, \"x\" | \"y\">): string[] => (state.y === null ? [state.x] : [state.x, state.y]);\n\n/** This function gives the values of a dimension in panels, inside the needs of the varied dimensions. */\nfunction panelLevels(record: ResponseRecord, state: Pick<ExplorerState, \"x\" | \"y\">, id: string): readonly ResponseValue[] {\n const stops = stopsOf(record, dimensionOf(record, id));\n const needed = neededLevels(record, variedOf(state)).get(id);\n return needed === undefined ? stops : stops.filter((value) => needed.includes(value));\n}\n\n/** This function gives the reason that a dimension cannot be in panels. A good dimension gives an empty string. */\nfunction facetBlock(record: ResponseRecord, state: Pick<ExplorerState, \"x\" | \"y\" | \"hold\">, dimension: ResponseDimension): string {\n if (variedOf(state).includes(dimension.id)) return \"It is on an axis\";\n const when = dimension.when;\n if (when !== undefined && !variedOf(state).includes(when.dimension) && !when.levels.includes(state.hold[when.dimension] as ResponseValue)) return `It applies ${whenText(record, dimension)}`;\n const count = panelLevels(record, state, dimension.id).length;\n if (count > MAX_PANELS) return `It has ${count} values, and a view has ${MAX_PANELS} panels or fewer`;\n if (count < 2) return \"It has one value here\";\n return \"\";\n}\n\n/** This function gives the reason that a dimension cannot go on an axis. A good dimension gives an empty string. */\nfunction axisBlock(record: ResponseRecord, state: ExplorerState, slot: AxisSlot, dimension: ResponseDimension): string {\n const otherId = slot === \"x\" ? state.y : state.x;\n if (dimension.id === otherId) return \"It is on the other axis\";\n const other = otherId === null ? undefined : dimensionOf(record, otherId);\n if (other?.when?.dimension === dimension.id) return `${other.label} needs it held`;\n const when = dimension.when;\n if (when === undefined) return \"\";\n const parent = dimensionOf(record, when.dimension);\n if (parent.id === otherId) return `It needs ${parent.label} held`;\n const shared = other?.when?.dimension === parent.id ? when.levels.filter((level) => other.when?.levels.includes(level) === true) : when.levels;\n const inView = parent.id === state.facet ? stopsOf(record, parent) : [state.hold[parent.id] as ResponseValue];\n return inView.some((level) => shared.includes(level)) ? \"\" : `It applies ${whenText(record, dimension)}`;\n}\n\n/** This function gives the first dimension with no condition, and a continuous dimension before another kind. */\nfunction firstAxis(record: ResponseRecord): string {\n const plain = record.dimensions.filter((d) => d.when === undefined);\n const chosen = plain.find((d) => d.kind === \"continuous\") ?? plain[0] ?? record.dimensions[0];\n return (chosen as ResponseDimension).id;\n}\n\n/**\n * This function gives the nearest good state for a wanted state. Each unknown or missing field takes its usual value.\n * A parent moves to a level that a varied conditional dimension needs. A combination that a view refuses loses its\n * second axis or its panels.\n */\nexport function settle(record: ResponseRecord, wanted: Partial<ExplorerState> = {}): ExplorerState {\n const known = (id: string | null | undefined): boolean => id !== null && id !== undefined && record.dimensions.some((d) => d.id === id);\n const measure = record.measures.some((m) => m.id === wanted.measure) ? (wanted.measure as string) : (record.measures[0]?.id ?? \"\");\n const x = known(wanted.x) ? (wanted.x as string) : firstAxis(record);\n const parentOf = (id: string): string | undefined => dimensionOf(record, id).when?.dimension;\n let y = known(wanted.y) && wanted.y !== x ? (wanted.y as string) : null;\n if (y !== null && (parentOf(y) === x || parentOf(x) === y || [...neededLevels(record, [x, y]).values()].some((levels) => levels.length === 0))) y = null;\n\n const hold: Record<string, ResponseValue> = {};\n for (const dimension of record.dimensions) hold[dimension.id] = nearestStop(record, dimension, wanted.hold?.[dimension.id]) ?? usualValue(record, dimension);\n\n const facetId = known(wanted.facet) ? (wanted.facet as string) : null;\n const facet = facetId !== null && facetBlock(record, { x, y, hold }, dimensionOf(record, facetId)) === \"\" ? facetId : null;\n for (const [parent, levels] of neededLevels(record, variedOf({ x, y }))) {\n if (parent === facet || levels.includes(hold[parent] as ResponseValue)) continue;\n hold[parent] = usualValue(record, dimensionOf(record, parent), levels);\n }\n return { measure, x, y, facet: facet !== null && facetBlock(record, { x, y, hold }, dimensionOf(record, facet)) === \"\" ? facet : null, hold };\n}\n\n/** This function gives each dimension as a choice for an axis. A disabled choice tells its reason. */\nexport function axisChoices(record: ResponseRecord, state: ExplorerState, slot: AxisSlot): readonly DimensionChoice[] {\n return record.dimensions.map((d) => {\n const reason = axisBlock(record, state, slot, d);\n return { id: d.id, label: d.label, disabled: reason !== \"\", reason };\n });\n}\n\n/** This function gives each dimension as a choice for panels. A disabled choice tells its reason. */\nexport function facetChoices(record: ResponseRecord, state: ExplorerState): readonly DimensionChoice[] {\n return record.dimensions.map((d) => {\n const reason = facetBlock(record, state, d);\n return { id: d.id, label: d.label, disabled: reason !== \"\", reason };\n });\n}\n\n/** This function gives the control of each held dimension. A dimension on an axis or in panels has no control. */\nexport function holdControls(record: ResponseRecord, state: ExplorerState): readonly HoldControl[] {\n const needed = neededLevels(record, variedOf(state));\n const held = record.dimensions.filter((d) => !variedOf(state).includes(d.id) && d.id !== state.facet);\n return held.map((d) => {\n const parent = d.when?.dimension;\n const open = parent === undefined || parent === state.facet || variedOf(state).includes(parent);\n const applies = open || d.when?.levels.includes(state.hold[parent as string] as ResponseValue) === true;\n const levels = needed.get(d.id);\n const options = stopsOf(record, d).map((value): HoldOption => {\n const locked = levels !== undefined && !levels.includes(value);\n const reason = !applies ? `It applies ${whenText(record, d)}` : locked ? \"A varied dimension has no value at this level\" : \"\";\n return { value, text: formatValue(value), disabled: reason !== \"\", reason };\n });\n const note = d.when === undefined ? \"\" : `Applies ${whenText(record, d)}`;\n return { id: d.id, label: d.label, kind: d.kind === \"continuous\" ? \"stops\" : \"levels\", applies, note, options, value: state.hold[d.id] as ResponseValue };\n });\n}\n\n/** This function gives the form of a group of levels. */\nexport function levelForm(count: number): \"chips\" | \"select\" {\n return count > MAX_CHIPS ? \"select\" : \"chips\";\n}\n\n/** This function gives the state with a new measure. */\nexport function setMeasure(record: ResponseRecord, state: ExplorerState, measure: string): ExplorerState {\n return settle(record, { ...state, measure });\n}\n\n/** This function gives the state with a new axis. It does not take a disabled choice. The value `null` removes the y axis. */\nexport function setAxis(record: ResponseRecord, state: ExplorerState, slot: AxisSlot, id: string | null): ExplorerState {\n if (id === null) return slot === \"y\" ? settle(record, { ...state, y: null }) : state;\n if (axisBlock(record, state, slot, dimensionOf(record, id)) !== \"\") return state;\n return settle(record, { ...state, [slot]: id, facet: state.facet === id ? null : state.facet });\n}\n\n/** This function gives the state with new panels. It does not take a disabled choice. The value `null` gives one panel. */\nexport function setFacet(record: ResponseRecord, state: ExplorerState, id: string | null): ExplorerState {\n if (id !== null && facetBlock(record, state, dimensionOf(record, id)) !== \"\") return state;\n return settle(record, { ...state, facet: id });\n}\n\n/** This function gives the state with a new held value. It does not take a disabled value. */\nexport function setHold(record: ResponseRecord, state: ExplorerState, id: string, value: ResponseValue): ExplorerState {\n const control = holdControls(record, state).find((c) => c.id === id);\n const option = control?.options.find((o) => o.value === value);\n if (option === undefined || option.disabled) return state;\n return settle(record, { ...state, hold: { ...state.hold, [id]: value } });\n}\n\n/**\n * This function gives the number of steps of a view, from the number of points, before the call. The field `nearest`\n * reads each point at each place, so the number of places comes from `READ_BUDGET`.\n *\n * @param points - The number of points of the record.\n * @param panels - The number of panels of the view.\n * @param continuous - The number of continuous axes of the view.\n * @param levels - The number of levels of a level axis of a surface, or 1.\n * @param cap - The largest result.\n */\nexport function planSteps(points: number, panels: number, continuous: number, levels: number, cap: number = MAX_STEPS): number {\n const places = READ_BUDGET / (Math.max(1, points) * Math.max(1, panels));\n const room = continuous === 2 ? Math.sqrt(places) : places / Math.max(1, levels);\n return Math.max(MIN_STEPS, Math.min(cap, MAX_STEPS, Math.floor(room)));\n}\n\n/** This function gives the cap of the next view: a smaller grid when this surface took more than the budget. */\nexport function nextStepsCap(steps: number, elapsedMs: number, budgetMs: number): number {\n if (elapsedMs <= budgetMs) return Number.POSITIVE_INFINITY;\n return Math.max(MIN_STEPS, Math.min(steps - 1, Math.floor(steps * Math.sqrt(budgetMs / elapsedMs))));\n}\n\n/** This function gives the axis of a dimension. */\nexport function axisOf(dimension: ResponseDimension): AxisSpec {\n const { id, label, unit } = dimension;\n const name = unit === \"\" ? label : `${label} (${unit})`;\n if (dimension.kind === \"continuous\") return { id, label: name, kind: \"number\", log: dimension.log === true, range: dimension.range, levels: [] };\n return { id, label: name, kind: \"levels\", log: false, range: [0, 1], levels: dimension.levels };\n}\n\n/** This function gives the place of a value on an axis, from 0 to 1. A value outside a number axis goes past the ends. */\nexport function placeOn(axis: AxisSpec, value: ResponseValue): number {\n if (axis.kind === \"levels\") return (axis.levels.indexOf(value) + 0.5) / axis.levels.length;\n const scale = (v: number): number => (axis.log ? Math.log10(v) : v);\n const [low, high] = axis.range;\n return (scale(value as number) - scale(low)) / (scale(high) - scale(low));\n}\n\n/** This function gives true for a point that matches the held values, with the rules of `sliceResponse`. */\nfunction pointMatches(record: ResponseRecord, point: ResponsePoint, measure: string, varied: readonly string[], hold: Readonly<Record<string, ResponseValue>>, tolerance: number): boolean {\n if (typeof point.measures[measure] !== \"number\") return false;\n return record.dimensions.every((d) => {\n const value = point.values[d.id] ?? null;\n if (varied.includes(d.id)) return value !== null;\n const wanted = whenHolds(d, point.values) ? (hold[d.id] as ResponseValue) : null;\n if (typeof value !== \"number\" || typeof wanted !== \"number\" || d.kind !== \"continuous\") return value === wanted;\n return Math.abs(shareOf(d, value) - shareOf(d, wanted)) <= tolerance;\n });\n}\n\n/** This function gives the error of a measure in plain words. */\nexport function errorSentence(measure: ResponseMeasure, model: ResponseModel, error: ResponseHeldOutError): string {\n const unit = measure.unit === \"\" ? \"\" : ` ${measure.unit}`;\n const amount = (value: number): string => (model.scale === \"log\" ? `a factor of ${formatValue(10 ** value)}` : `${formatValue(value)}${unit}`);\n const seen = `On ${error.n} points that each fit did not see, over ${error.folds} folds, the model misses by ${amount(error.mae)} on average.`;\n const base = `A plain mean misses by ${amount(error.baselineMae)}.`;\n if (error.skill === null) return `${seen} ${base}`;\n return error.skill > 0 ? `${seen} ${base} The model removes ${Math.round(error.skill * 100)}% of that miss.` : `${seen} ${base} The model is no better than the mean.`;\n}\n\n/** This function gives the name of a panel. */\nconst panelTitle = (facet: ResponseDimension | undefined, level: ResponseValue | null): string => (facet === undefined || level === null ? \"\" : `${facet.label}: ${formatValue(level)}`);\n\n/** This function gives the panels of a measure with no model: the measured points that match the held values. */\nfunction pointPanels(record: ResponseRecord, state: ExplorerState, levels: readonly (ResponseValue | null)[], facet: ResponseDimension | undefined, tolerance: number): ExplorerPanel[] {\n const varied = variedOf(state);\n return levels.map((level) => {\n const hold = level === null || facet === undefined ? state.hold : { ...state.hold, [facet.id]: level };\n const points = record.points.flatMap((p): PlainPoint[] => {\n if (!pointMatches(record, p, state.measure, varied, hold, tolerance)) return [];\n return [{ id: p.id, at: varied.map((id) => p.values[id] as ResponseValue), value: p.measures[state.measure] as number }];\n });\n return { kind: \"points\", title: panelTitle(facet, level), level, points };\n });\n}\n\n/** This function gives the held values of a request: each dimension that does not vary. */\nfunction requestHold(state: ExplorerState, facet: ResponseDimension | undefined, level: ResponseValue | null): Record<string, ResponseValue> {\n const varied = variedOf(state);\n const hold = Object.fromEntries(Object.entries(state.hold).filter(([id]) => !varied.includes(id)));\n return facet === undefined || level === null ? hold : { ...hold, [facet.id]: level };\n}\n\n/** This function gives the text of the size of a grid. */\nfunction gridSentence(x: readonly ResponseValue[], y: readonly ResponseValue[], cells: boolean, elapsedMs: number, budgetMs: number): string {\n if (cells) return `The grid has ${x.length} by ${y.length} measured levels.`;\n const size = `The grid has ${x.length} by ${y.length} places.`;\n return elapsedMs > budgetMs ? `${size} This surface took ${Math.round(elapsedMs)} ms, so the next grid is smaller.` : size;\n}\n\n/** This function gives the text of the places that a range moved. A view with no such place gives an empty string. */\nfunction rangeSentence(measure: ResponseMeasure, panels: readonly ExplorerPanel[]): string {\n const moved = panels.reduce((count, panel) => count + (panel.kind === \"curve\" ? panel.slice.clipped : panel.kind === \"surface\" ? panel.surface.clipped : 0), 0);\n if (moved === 0 || measure.range === undefined) return \"\";\n return `At ${moved} ${moved === 1 ? \"place\" : \"places\"}, the view stops at the range of the measure, ${measure.range[0]} to ${measure.range[1]}.`;\n}\n\n/** This function gives the steps of a view from its axes and the plan of `planSteps`. */\nfunction stepsOfView(record: ResponseRecord, state: ExplorerState, panels: number, cap: number): number {\n const continuous = variedOf(state).filter((id) => dimensionOf(record, id).kind === \"continuous\").length;\n // A count at 2 steps, less the 2 of each continuous axis, leaves the levels of the other axes.\n const levels = responseCells(record, state.y === null ? state.x : [state.x, state.y], 2) / 2 ** continuous;\n return planSteps(record.points.length, panels, continuous, levels, cap);\n}\n\n/**\n * This function gives the data of a view. It does not throw. A request that the record refuses gives the text in\n * `problem`, and no panels. A measure with no model gives only the measured points, and a table model gives cells.\n * A smooth model that is no better than a plain mean also gives only the measured points. A drawn fit claims knowledge that such a model does not have.\n * A table model keeps its cells at any error, because each cell is the mean of measured points.\n */\nexport function viewOf(record: ResponseRecord, state: ExplorerState, options: ViewOptions = {}): ExplorerView {\n const { budgetMs = SURFACE_BUDGET_MS, stepsCap = MAX_STEPS, now = (): number => 0 } = options;\n const measure = record.measures.find((m) => m.id === state.measure) ?? (record.measures[0] as ResponseMeasure);\n const model = record.models.find((m) => m.measure === measure.id);\n const x = axisOf(dimensionOf(record, state.x));\n const y = state.y === null ? null : axisOf(dimensionOf(record, state.y));\n const facet = state.facet === null ? undefined : dimensionOf(record, state.facet);\n const levels = facet === undefined ? [null] : panelLevels(record, state, facet.id);\n const steps = stepsOfView(record, state, levels.length, stepsCap);\n const tolerance = toleranceOf(record);\n const base = { measure, x, y, log: model?.scale === \"log\", steps, elapsedMs: 0, nextCap: stepsCap, gridText: \"\", rangeText: \"\", problem: \"\" };\n\n if (model === undefined) {\n const modelText = \"This measure has no valid model in the record, so the view shows only the measured points.\";\n return { ...base, panels: pointPanels(record, state, levels, facet, tolerance), error: null, errorText: \"\", modelText };\n }\n const modelText = model.kind === \"table\" ? \"The model is the mean of each measured cell, so the view shows cells and no smooth surface.\" : \"The model is a smooth fit over all the dimensions.\";\n try {\n const heldOut = heldOutError(record, measure.id);\n if (model.kind !== \"table\" && heldOut.skill !== null && heldOut.skill <= 0) {\n const noBetter = \"The model is no better than a plain mean on points that it did not see, so the view shows only the measured points.\";\n return { ...base, panels: pointPanels(record, state, levels, facet, tolerance), error: heldOut, errorText: errorSentence(measure, model, heldOut), modelText: noBetter };\n }\n const start = now();\n const panels = levels.map((level): ExplorerPanel => {\n const hold = requestHold(state, facet, level);\n const title = panelTitle(facet, level);\n if (state.y === null) return { kind: \"curve\", title, level, slice: sliceResponse(record, measure.id, { vary: state.x, hold, steps, tolerance }) };\n const surface = surfaceResponse(record, measure.id, { vary: [state.x, state.y], hold, steps, tolerance });\n return { kind: \"surface\", title, level, cells: model.kind === \"table\" || (x.kind === \"levels\" && y?.kind === \"levels\"), surface };\n });\n const elapsedMs = Math.max(0, now() - start);\n const first = panels[0];\n const surface = first?.kind === \"surface\" ? first : undefined;\n const late = surface !== undefined && !surface.cells ? nextStepsCap(steps, elapsedMs, budgetMs) : Number.POSITIVE_INFINITY;\n const gridText = surface === undefined ? \"\" : gridSentence(surface.surface.x, surface.surface.y, surface.cells, elapsedMs, budgetMs);\n return { ...base, panels, error: heldOut, errorText: errorSentence(measure, model, heldOut), modelText, gridText, rangeText: rangeSentence(measure, panels), elapsedMs, nextCap: Math.min(stepsCap, late) };\n } catch (error) {\n return { ...base, panels: [], error: null, errorText: \"\", modelText, problem: error instanceof Error ? error.message : String(error) };\n }\n}\n\n/** This function gives the strength of the band at a distance from a measurement: 1 at a measurement, 0.15 far away. */\nexport function fadeOf(nearest: number): number {\n return 1 - 0.85 * Math.min(1, nearest / FADE_END);\n}\n\n/** This function gives the share of the neutral veil of a surface cell at a distance from a measurement. */\nexport function veilOf(nearest: number): number {\n return 0.8 * Math.min(1, nearest / FADE_END);\n}\n\n/** This function gives a round step for a range and a tick count: 1, 2 or 5 times a power of 10. */\nfunction roundStep(span: number, count: number): number {\n const raw = span / Math.max(1, count);\n const power = 10 ** Math.floor(Math.log10(raw));\n const share = raw / power;\n return (share <= 1 ? 1 : share <= 2 ? 2 : share <= 5 ? 5 : 10) * power;\n}\n\n/** This function gives round numbers in a range, for approximately `count` ticks. */\nfunction roundNumbers(low: number, high: number, count: number): number[] {\n if (!(high > low)) return [low];\n const step = roundStep(high - low, count);\n const out: number[] = [];\n for (let i = Math.ceil(low / step - 1e-9); i * step <= high + step * 1e-9; i++) out.push(Number((i * step).toPrecision(12)));\n return out;\n}\n\n/** This function gives the values 1, 2 and 5 times each power of 10 in a range, for approximately `count` ticks. */\nfunction logNumbers(low: number, high: number, count: number): number[] {\n const out: number[] = [];\n for (let power = Math.floor(Math.log10(low)); power <= Math.ceil(Math.log10(high)); power++) {\n for (const factor of [1, 2, 5]) {\n const value = Number((factor * 10 ** power).toPrecision(12));\n if (value >= low * (1 - 1e-9) && value <= high * (1 + 1e-9)) out.push(value);\n }\n }\n const powers = out.filter((value) => Number.isInteger(Math.log10(value)));\n return out.length > count && powers.length >= 2 ? powers : out;\n}\n\n/** This function gives the ticks of a number range. A log range with too few round values gives linear round values. */\nexport function numberTicks(low: number, high: number, log: boolean, count: number): readonly Tick[] {\n const scale = (v: number): number => (log ? Math.log10(v) : v);\n const logged = log ? logNumbers(low, high, count) : [];\n const values = logged.length >= 3 ? logged : roundNumbers(low, high, count);\n return values.map((value) => ({ place: high > low ? (scale(value) - scale(low)) / (scale(high) - scale(low)) : 0.5, text: formatValue(value) }));\n}\n\n/** This function gives the ticks of an axis. */\nexport function axisTicks(axis: AxisSpec, count: number): readonly Tick[] {\n if (axis.kind === \"number\") return numberTicks(axis.range[0], axis.range[1], axis.log, count);\n return axis.levels.map((level) => ({ place: placeOn(axis, level), text: formatValue(level) }));\n}\n\n/** This function gives the values of one panel that the value axis must show. */\nfunction panelValues(panel: ExplorerPanel, varied: number): number[] {\n if (panel.kind === \"points\") return varied === 1 ? panel.points.map((p) => p.value) : [];\n if (panel.kind === \"curve\") return [...panel.slice.curve.flatMap((c) => [c.low, c.high]), ...panel.slice.points.map((p) => p.value)];\n return [];\n}\n\n/**\n * This function gives the two ends of the value axis of a curve view. All the panels of a view share them, so two\n * panels compare by eye. A range of one value grows, so the axis keeps a length.\n */\nexport function valueRange(view: ExplorerView): readonly [number, number] {\n const values = view.panels.flatMap((panel) => panelValues(panel, view.y === null ? 1 : 2)).filter((v) => Number.isFinite(v) && (!view.log || v > 0));\n if (values.length === 0) return view.log ? [1, 10] : [0, 1];\n const low = Math.min(...values);\n const high = Math.max(...values);\n if (view.log) {\n const margin = high > low ? (high / low) ** 0.05 : 2;\n return [low / margin, high * margin];\n }\n const margin = high > low ? (high - low) * 0.05 : Math.max(Math.abs(low) * 0.1, 1);\n return [low - margin, high + margin];\n}\n\n/** This function gives each fitted value of a surface view, with the values of a view of plain points. */\nfunction heatValues(view: ExplorerView): number[] {\n return view.panels.flatMap((panel) => {\n if (panel.kind === \"surface\") return panel.surface.cells.flatMap((row) => row.map((cell) => cell.value));\n return panel.kind === \"points\" ? panel.points.map((p) => p.value) : [];\n });\n}\n\n/** This function gives the two ends of the color scale of a surface view. All the panels share them. */\nexport function heatRange(view: ExplorerView): readonly [number, number] {\n const values = heatValues(view).filter((v) => Number.isFinite(v) && (!view.log || v > 0));\n if (values.length === 0) return [0, 1];\n return [Math.min(...values), Math.max(...values)];\n}\n\n/** This function gives the step of the color scale of a value, from 0 to `HEAT_STEPS - 1`. */\nexport function heatStep(value: number, range: readonly [number, number], log: boolean): number {\n const [low, high] = range;\n if (!(high > low)) return Math.floor(HEAT_STEPS / 2);\n const share = log ? (Math.log10(value) - Math.log10(low)) / (Math.log10(high) - Math.log10(low)) : (value - low) / (high - low);\n return Math.max(0, Math.min(HEAT_STEPS - 1, Math.floor(share * HEAT_STEPS)));\n}\n\n/** This function gives the edges of the cells around places on an axis, from 0 to 1. There is one more edge than places. */\nexport function cellEdges(places: readonly number[]): readonly number[] {\n const inner = places.slice(1).map((place, i) => (place + (places[i] as number)) / 2);\n return [0, ...inner, 1];\n}\n\n/** A point of a path, in the pixels of a chart. */\nexport type Pixel = readonly [number, number];\n\n/** This function gives the path of a line through pixels. */\nexport function linePath(pixels: readonly Pixel[]): string {\n return pixels.map(([x, y], i) => `${i === 0 ? \"M\" : \"L\"}${x.toFixed(1)} ${y.toFixed(1)}`).join(\"\");\n}\n\n/** This function gives the closed path of a band between its upper and its lower pixels. */\nexport function bandPath(upper: readonly Pixel[], lower: readonly Pixel[]): string {\n return `${linePath([...upper, ...[...lower].reverse()])}Z`;\n}\n\n/** This function gives the distance from a measurement in plain words. */\nfunction nearText(nearest: number): string {\n return nearest === 0 ? \"A point was measured here.\" : `The nearest measured point is ${Math.round(nearest * 100)}% of an axis away.`;\n}\n\n/** This function gives the text of one place of a band. */\nfunction bandText(band: ResponseBand): string {\n return `fitted ${formatValue(band.value)}, band ${formatValue(band.low)} to ${formatValue(band.high)}. ${nearText(band.nearest)}`;\n}\n\n/** This function gives the text of one place of a curve. */\nexport function curveText(axis: AxisSpec, place: ResponseCurvePoint): string {\n return `${axis.label} ${formatValue(place.at)}: ${bandText(place)}`;\n}\n\n/** This function gives the text of one place of a surface. */\nexport function cellText(x: AxisSpec, y: AxisSpec, atX: ResponseValue, atY: ResponseValue, band: ResponseBand): string {\n return `${x.label} ${formatValue(atX)}, ${y.label} ${formatValue(atY)}: ${bandText(band)}`;\n}\n\n/** This function gives the numbers of a panel: each place of a curve, or the measured points of a surface. */\nexport function numberTable(view: ExplorerView, panel: ExplorerPanel): NumberTable {\n const axes = view.y === null ? [view.x.label] : [view.x.label, view.y.label];\n if (panel.kind === \"curve\") {\n const rows = panel.slice.curve.map((c) => [formatValue(c.at), formatValue(c.value), formatValue(c.low), formatValue(c.high), `${Math.round(c.nearest * 100)}%`]);\n return { columns: [view.x.label, \"Fitted\", \"Low\", \"High\", \"Distance\"], rows };\n }\n const points: readonly { readonly at: readonly ResponseValue[]; readonly value: number }[] = panel.kind === \"points\" ? panel.points : panel.surface.points;\n return { columns: [...axes, \"Measured\"], rows: points.map((p) => [...p.at.map(formatValue), formatValue(p.value)]) };\n}\n","/// <reference lib=\"dom\" />\n/**\n * The DOM view of the response explorer. This module draws SVG with no framework. The core in `model.ts` gives each\n * rule and each number, and this module connects the core to the page.\n */\n\nimport { h, type Child } from \"../chrome.ts\";\nimport {\n axisChoices,\n axisTicks,\n bandPath,\n cellEdges,\n cellText,\n curveText,\n facetChoices,\n fadeOf,\n formatValue,\n heatRange,\n heatStep,\n HEAT_STEPS,\n holdControls,\n levelForm,\n linePath,\n MAX_STEPS,\n numberTable,\n numberTicks,\n openRecord,\n placeOn,\n setAxis,\n setFacet,\n setHold,\n setMeasure,\n settle,\n SURFACE_BUDGET_MS,\n valueRange,\n veilOf,\n viewOf,\n type AxisSpec,\n type CurvePanel,\n type DimensionChoice,\n type ExplorerPanel,\n type ExplorerState,\n type ExplorerView,\n type HoldControl,\n type Pixel,\n type PointsPanel,\n type SurfacePanel,\n type Tick,\n} from \"./model.ts\";\nimport type { ResponseRecord, ResponseValue } from \"@mark1russell7/rigor-statistics\";\n\n/** The options of `mountExplorer`. */\nexport interface ExplorerOptions {\n /** The first state. The explorer corrects a state that a record refuses. */\n readonly initial?: Partial<ExplorerState>;\n /** The time of a surface in milliseconds. The default is `SURFACE_BUDGET_MS`. */\n readonly budgetMs?: number;\n /** The clock in milliseconds. The default is `performance.now`. */\n readonly now?: () => number;\n}\n\n/** The result of `mountExplorer`. */\nexport interface ExplorerHandle {\n /** This method gives the choices of the visitor. It gives `null` for a record with faults. */\n state(): ExplorerState | null;\n /** This method removes the explorer from its host. */\n destroy(): void;\n}\n\nconst SVG = \"http://www.w3.org/2000/svg\";\n/** The most faults that the view lists. */\nconst MAX_FAULTS = 20;\n/** The width of a chart with no layout, for example in a test. */\nconst FALLBACK_WIDTH = 640;\nconst MARGIN = { top: 10, right: 14, bottom: 42, left: 50 };\n/** The height of a line of text of an axis, in pixels. */\nconst CHAR_WIDTH = 6.4;\n\nlet mounts = 0;\n\n/** This function makes an SVG element with attributes and children. */\nfunction s(tag: string, attrs: Readonly<Record<string, string | number>>, ...children: readonly (Node | string)[]): SVGElement {\n const el = document.createElementNS(SVG, tag);\n for (const [name, value] of Object.entries(attrs)) el.setAttribute(name, String(value));\n el.append(...children);\n return el;\n}\n\n/** The plot of a chart: the pixels of its area and of its axes. */\ninterface Plot {\n readonly width: number;\n readonly height: number;\n readonly left: number;\n readonly top: number;\n readonly right: number;\n readonly bottom: number;\n}\n\n/** This function gives the plot of a chart. Long level names need room for their turned text. */\nfunction plotOf(width: number, height: number, view: ExplorerView): Plot {\n const turned = turnedLevels(view.x, width - MARGIN.left - MARGIN.right);\n const longest = Math.max(0, ...view.x.levels.map((level) => formatValue(level).length));\n const bottom = height - MARGIN.bottom - (turned ? Math.min(60, longest * CHAR_WIDTH * 0.7) : 0);\n const left = view.y?.kind === \"levels\" ? Math.min(110, Math.max(MARGIN.left, 12 + Math.max(...view.y.levels.map((level) => formatValue(level).length)) * CHAR_WIDTH)) : MARGIN.left;\n return { width, height, left, top: MARGIN.top, right: width - MARGIN.right, bottom };\n}\n\n/** This function gives true when the levels of an axis do not fit side by side. */\nfunction turnedLevels(axis: AxisSpec, room: number): boolean {\n if (axis.kind !== \"levels\") return false;\n const longest = Math.max(0, ...axis.levels.map((level) => formatValue(level).length));\n return (longest + 1) * CHAR_WIDTH > room / Math.max(1, axis.levels.length);\n}\n\n/** This function gives the ticks of an axis that fit in a length. */\nfunction fittedTicks(axis: AxisSpec, length: number): readonly Tick[] {\n return axisTicks(axis, Math.max(2, Math.floor(length / 70)));\n}\n\n/** This function draws the horizontal axis. */\nfunction xAxis(plot: Plot, axis: AxisSpec): SVGElement {\n const length = plot.right - plot.left;\n const turned = turnedLevels(axis, length);\n const ticks = fittedTicks(axis, length).map((tick) => {\n const x = plot.left + tick.place * length;\n const label = turned\n ? s(\"text\", { class: \"rx-tick\", x, y: plot.bottom + 14, \"text-anchor\": \"end\", transform: `rotate(-35 ${x} ${plot.bottom + 14})` }, tick.text)\n : s(\"text\", { class: \"rx-tick\", x, y: plot.bottom + 15, \"text-anchor\": x + (tick.text.length * CHAR_WIDTH) / 2 > plot.width ? \"end\" : \"middle\" }, tick.text);\n return s(\"g\", {}, s(\"line\", { class: \"rx-axis\", x1: x, x2: x, y1: plot.bottom, y2: plot.bottom + 4 }), label);\n });\n const name = s(\"text\", { class: \"rx-axis-name\", x: (plot.left + plot.right) / 2, y: plot.height - 6, \"text-anchor\": \"middle\" }, axis.log ? `${axis.label}, log scale` : axis.label);\n return s(\"g\", {}, s(\"line\", { class: \"rx-axis\", x1: plot.left, x2: plot.right, y1: plot.bottom, y2: plot.bottom }), ...ticks, name);\n}\n\n/** This function draws the value axis with its grid lines. */\nfunction valueAxis(plot: Plot, ticks: readonly Tick[]): SVGElement {\n const length = plot.bottom - plot.top;\n const lines = ticks.map((tick) => {\n const y = plot.bottom - tick.place * length;\n return s(\"g\", {}, s(\"line\", { class: \"rx-grid\", x1: plot.left, x2: plot.right, y1: y, y2: y }), s(\"text\", { class: \"rx-tick\", x: plot.left - 6, y: y + 4, \"text-anchor\": \"end\" }, tick.text));\n });\n return s(\"g\", {}, ...lines);\n}\n\n/** This function draws the vertical axis of a surface. */\nfunction surfaceAxis(plot: Plot, axis: AxisSpec): SVGElement {\n const length = plot.bottom - plot.top;\n const ticks = axisTicks(axis, Math.max(2, Math.floor(length / 45))).map((tick) => {\n const y = plot.bottom - tick.place * length;\n return s(\"text\", { class: \"rx-tick\", x: plot.left - 6, y: y + 4, \"text-anchor\": \"end\" }, tick.text);\n });\n return s(\"g\", {}, ...ticks);\n}\n\n/** The scale of the value axis of a view. */\ninterface ValueScale {\n readonly range: readonly [number, number];\n readonly log: boolean;\n}\n\n/** This function gives the place of a value on the value axis, from 0 to 1. */\nfunction valuePlace(scale: ValueScale, value: number): number {\n const [low, high] = scale.range;\n if (scale.log) return (Math.log10(Math.max(value, low)) - Math.log10(low)) / (Math.log10(high) - Math.log10(low));\n return (value - low) / (high - low);\n}\n\n/** This function gives a small steady offset for a dot from its id, so the dots of one level do not all overlap. */\nfunction jitter(id: string, room: number): number {\n let hash = 7;\n for (const char of id) hash = (hash * 31 + (char.codePointAt(0) ?? 0)) % 1009;\n return (hash / 1008 - 0.5) * room;\n}\n\n/** The handler of a panel: it moves the mark of the cursor and it gives the text of a place. */\ninterface Cursor {\n /** The number of places across and up. */\n readonly columns: number;\n readonly rows: number;\n /** This method gives the place at a pixel. */\n at(x: number, y: number): readonly [number, number];\n /** This method moves the mark and gives the text of the place. */\n show(column: number, row: number): string;\n}\n\n/** This function connects the pointer and the arrow keys of a chart to its cursor. */\nfunction connect(svg: SVGElement, cursor: Cursor, tell: (text: string) => void): void {\n let column = -1;\n let row = 0;\n const move = (nextColumn: number, nextRow: number): void => {\n column = Math.max(0, Math.min(cursor.columns - 1, nextColumn));\n row = Math.max(0, Math.min(cursor.rows - 1, nextRow));\n tell(cursor.show(column, row));\n };\n svg.addEventListener(\"pointermove\", (event) => {\n const box = svg.getBoundingClientRect();\n const [c, r] = cursor.at((event as PointerEvent).clientX - box.left, (event as PointerEvent).clientY - box.top);\n move(c, r);\n });\n svg.addEventListener(\"keydown\", (event) => {\n const steps: Readonly<Record<string, readonly [number, number]>> = { ArrowLeft: [-1, 0], ArrowRight: [1, 0], ArrowUp: [0, -1], ArrowDown: [0, 1] };\n const step = steps[(event as KeyboardEvent).key];\n if (step === undefined) return;\n event.preventDefault();\n move(column < 0 ? 0 : column + step[0], row + step[1]);\n });\n}\n\n/** This function makes the frame of a chart with its text for a screen reader. */\nfunction chartFrame(plot: Plot, label: string): SVGElement {\n return s(\"svg\", { class: \"rx-svg\", width: plot.width, height: plot.height, viewBox: `0 0 ${plot.width} ${plot.height}`, role: \"img\", \"aria-label\": label, tabindex: 0 });\n}\n\n/** This function draws a band with one strength for each place along the axis. */\nfunction fadedBand(plot: Plot, panel: CurvePanel, scale: ValueScale, axis: AxisSpec, id: string): SVGElement[] {\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const curve = panel.slice.curve;\n const px = (at: ResponseValue): number => plot.left + placeOn(axis, at) * length;\n const py = (value: number): number => plot.bottom - valuePlace(scale, value) * height;\n const stops = curve.map((place) => s(\"stop\", { class: \"rx-band-stop\", offset: placeOn(axis, place.at), \"stop-opacity\": fadeOf(place.nearest).toFixed(3) }));\n const gradient = s(\"linearGradient\", { id, gradientUnits: \"userSpaceOnUse\", x1: plot.left, x2: plot.right, y1: 0, y2: 0 }, ...stops);\n const upper = curve.map((place): Pixel => [px(place.at), py(place.high)]);\n const lower = curve.map((place): Pixel => [px(place.at), py(place.low)]);\n return [s(\"defs\", {}, gradient), s(\"path\", { class: \"rx-band\", d: bandPath(upper, lower), fill: `url(#${id})` })];\n}\n\n/** This function draws a band and a mark at each level of a level axis. */\nfunction levelMarks(plot: Plot, panel: CurvePanel, scale: ValueScale, axis: AxisSpec): SVGElement[] {\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const room = Math.min(44, (length / Math.max(1, axis.levels.length)) * 0.5);\n return panel.slice.curve.flatMap((place) => {\n const x = plot.left + placeOn(axis, place.at) * length;\n const top = plot.bottom - valuePlace(scale, place.high) * height;\n const bottom = plot.bottom - valuePlace(scale, place.low) * height;\n const y = plot.bottom - valuePlace(scale, place.value) * height;\n return [\n s(\"rect\", { class: \"rx-whisker\", x: x - room / 2, y: top, width: room, height: Math.max(1, bottom - top), rx: 4, \"fill-opacity\": (0.3 * fadeOf(place.nearest)).toFixed(3) }),\n s(\"line\", { class: \"rx-line\", x1: x - room / 2, x2: x + room / 2, y1: y, y2: y }),\n ];\n });\n}\n\n/** This function draws a chart with a fitted curve, its band and the measured points. */\nfunction curveChart(view: ExplorerView, panel: CurvePanel, width: number, id: string, tell: (text: string) => void): SVGElement {\n const plot = plotOf(width, 270, view);\n const scale: ValueScale = { range: valueRange(view), log: view.log };\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const curve = panel.slice.curve;\n const px = (at: ResponseValue): number => plot.left + placeOn(view.x, at) * length;\n const py = (value: number): number => plot.bottom - valuePlace(scale, value) * height;\n const smooth = view.x.kind === \"number\";\n const marks = smooth\n ? [...fadedBand(plot, panel, scale, view.x, id), s(\"path\", { class: \"rx-line\", d: linePath(curve.map((place): Pixel => [px(place.at), py(place.value)])) })]\n : levelMarks(plot, panel, scale, view.x);\n const room = smooth ? 0 : Math.min(30, (length / Math.max(1, view.x.levels.length)) * 0.35);\n const dots = panel.slice.points.map((point) => s(\"circle\", { class: \"rx-dot\", cx: px(point.at) + jitter(point.id, room), cy: py(point.value), r: 3.5 }));\n const ticks = numberTicks(scale.range[0], scale.range[1], scale.log, Math.max(2, Math.floor(height / 50)));\n const rule = s(\"line\", { class: \"rx-cursor\", x1: 0, x2: 0, y1: plot.top, y2: plot.bottom, visibility: \"hidden\" });\n const ring = s(\"circle\", { class: \"rx-ring\", cx: 0, cy: 0, r: 5, visibility: \"hidden\" });\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label} over ${view.x.label}.`.trim());\n svg.append(valueAxis(plot, ticks), ...marks, ...dots, xAxis(plot, view.x), rule, ring);\n connect(\n svg,\n {\n columns: curve.length,\n rows: 1,\n at: (x) => {\n const distance = (place: (typeof curve)[number]): number => Math.abs(px(place.at) - x);\n const nearest = curve.reduce((best, place) => (distance(place) < distance(best) ? place : best));\n return [curve.indexOf(nearest), 0];\n },\n show: (column) => {\n const place = curve[column] as (typeof curve)[number];\n for (const [name, value] of [[\"x1\", px(place.at)], [\"x2\", px(place.at)]] as const) rule.setAttribute(name, String(value));\n ring.setAttribute(\"cx\", String(px(place.at)));\n ring.setAttribute(\"cy\", String(py(place.value)));\n rule.setAttribute(\"visibility\", \"visible\");\n ring.setAttribute(\"visibility\", \"visible\");\n return curveText(view.x, place);\n },\n },\n tell,\n );\n return svg;\n}\n\n/** This function draws a chart of a surface, or the separate cells of a table. */\nfunction surfaceChart(view: ExplorerView, panel: SurfacePanel, width: number, tell: (text: string) => void): SVGElement {\n const axisY = view.y as AxisSpec;\n const plot = plotOf(width, Math.min(380, Math.max(280, width * 0.72)), view);\n const { x, y, cells } = panel.surface;\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const xEdges = cellEdges(x.map((value) => placeOn(view.x, value)));\n const yEdges = cellEdges(y.map((value) => placeOn(axisY, value)));\n const range = heatRange(view);\n const gap = panel.cells ? 2 : 0;\n const cellMarks = cells.flatMap((row, j) =>\n row.flatMap((band, i) => {\n const left = plot.left + (xEdges[i] as number) * length;\n const right = plot.left + (xEdges[i + 1] as number) * length;\n const lower = plot.bottom - (yEdges[j] as number) * height;\n const upper = plot.bottom - (yEdges[j + 1] as number) * height;\n const box = { x: left + gap / 2, y: upper + gap / 2, width: Math.max(0.5, right - left - gap + (gap === 0 ? 0.6 : 0)), height: Math.max(0.5, lower - upper - gap + (gap === 0 ? 0.6 : 0)) };\n const step = heatStep(band.value, range, view.log);\n const parts = [s(\"rect\", { ...box, class: `rx-h${step}` })];\n const veil = veilOf(band.nearest);\n if (veil > 0.02) parts.push(s(\"rect\", { ...box, class: \"rx-veil\", \"fill-opacity\": veil.toFixed(3) }));\n if (panel.cells && box.width > 34 && box.height > 18) parts.push(s(\"text\", { class: `rx-cell-text ${step > HEAT_STEPS / 2 ? \"rx-on-dark\" : \"rx-on-light\"}`, x: box.x + box.width / 2, y: box.y + box.height / 2 + 4, \"text-anchor\": \"middle\" }, formatValue(band.value)));\n return parts;\n }),\n );\n const dots = panel.surface.points.map((point) =>\n s(\"circle\", { class: \"rx-dot rx-dot-heat\", cx: plot.left + placeOn(view.x, point.at[0]) * length + jitter(point.id, 6), cy: plot.bottom - placeOn(axisY, point.at[1]) * height + jitter(`${point.id}y`, 6), r: 2.5 }),\n );\n const outline = s(\"rect\", { class: \"rx-cell-cursor\", x: 0, y: 0, width: 0, height: 0, visibility: \"hidden\" });\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label} over ${view.x.label} and ${axisY.label}.`.trim());\n svg.append(...cellMarks, ...dots, surfaceAxis(plot, axisY), xAxis(plot, view.x), outline);\n const find = (edges: readonly number[], share: number): number => {\n const index = edges.findIndex((edge) => edge > share);\n return Math.max(0, (index < 0 ? edges.length : index) - 1);\n };\n connect(\n svg,\n {\n columns: x.length,\n rows: y.length,\n at: (px, py) => [find(xEdges, (px - plot.left) / length), y.length - 1 - find(yEdges, (plot.bottom - py) / height)],\n show: (column, row) => {\n const j = y.length - 1 - row;\n outline.setAttribute(\"x\", String(plot.left + (xEdges[column] as number) * length));\n outline.setAttribute(\"width\", String(((xEdges[column + 1] as number) - (xEdges[column] as number)) * length));\n outline.setAttribute(\"y\", String(plot.bottom - (yEdges[j + 1] as number) * height));\n outline.setAttribute(\"height\", String(((yEdges[j + 1] as number) - (yEdges[j] as number)) * height));\n outline.setAttribute(\"visibility\", \"visible\");\n return cellText(view.x, axisY, x[column] as ResponseValue, y[j] as ResponseValue, cells[j]?.[column] as (typeof cells)[number][number]);\n },\n },\n tell,\n );\n return svg;\n}\n\n/** This function draws the measured points of a measure with no model. */\nfunction pointsChart(view: ExplorerView, panel: PointsPanel, width: number): SVGElement {\n const plot = plotOf(width, 270, view);\n const length = plot.right - plot.left;\n const height = plot.bottom - plot.top;\n const svg = chartFrame(plot, `${panel.title} ${view.measure.label}: ${panel.points.length} measured points.`.trim());\n if (view.y === null) {\n const scale: ValueScale = { range: valueRange(view), log: view.log };\n const room = view.x.kind === \"levels\" ? Math.min(30, (length / Math.max(1, view.x.levels.length)) * 0.35) : 0;\n const dots = panel.points.map((point) => s(\"circle\", { class: \"rx-dot\", cx: plot.left + placeOn(view.x, point.at[0] as ResponseValue) * length + jitter(point.id, room), cy: plot.bottom - valuePlace(scale, point.value) * height, r: 3.5 }));\n const ticks = numberTicks(scale.range[0], scale.range[1], scale.log, Math.max(2, Math.floor(height / 50)));\n svg.append(valueAxis(plot, ticks), ...dots, xAxis(plot, view.x));\n return svg;\n }\n const axisY = view.y;\n const range = heatRange(view);\n const dots = panel.points.map((point) =>\n s(\"circle\", { class: `rx-h${heatStep(point.value, range, view.log)} rx-ring-dot`, cx: plot.left + placeOn(view.x, point.at[0] as ResponseValue) * length + jitter(point.id, 8), cy: plot.bottom - placeOn(axisY, point.at[1] as ResponseValue) * height + jitter(`${point.id}y`, 8), r: 5 }),\n );\n svg.append(...dots, surfaceAxis(plot, axisY), xAxis(plot, view.x));\n return svg;\n}\n\n/** This function gives the number of measured points of a panel. */\nfunction pointCount(panel: ExplorerPanel): number {\n if (panel.kind === \"curve\") return panel.slice.points.length;\n return panel.kind === \"surface\" ? panel.surface.points.length : panel.points.length;\n}\n\n/** This function gives the sentence about the measured points of a panel. */\nfunction pointsText(panel: ExplorerPanel): string {\n const count = pointCount(panel);\n if (count === 0) return \"No measured point has these held values.\";\n return count === 1 ? \"1 measured point has these held values.\" : `${count} measured points have these held values.`;\n}\n\n/** This function draws one panel. */\nfunction panelChart(view: ExplorerView, panel: ExplorerPanel, width: number, id: string, tell: (text: string) => void): SVGElement {\n if (panel.kind === \"curve\") return curveChart(view, panel, width, id, tell);\n return panel.kind === \"surface\" ? surfaceChart(view, panel, width, tell) : pointsChart(view, panel, width);\n}\n\n/** This function makes the legend of a view. */\nfunction legendOf(view: ExplorerView): HTMLElement {\n const item = (mark: HTMLElement, text: string): HTMLElement => h(\"span\", { class: \"rx-key\" }, mark, text);\n const mark = (name: string): HTMLElement => h(\"i\", { class: `rx-mark ${name}`, \"aria-hidden\": \"true\" });\n const parts: Child[] = [];\n const panel = view.panels[0];\n const surface = view.y !== null && panel?.kind !== \"curve\";\n if (panel?.kind === \"curve\") parts.push(item(mark(\"rx-mark-line\"), \"fitted value\"), item(mark(\"rx-mark-band\"), \"band: one held-out error each side. It fades away from the data.\"));\n if (surface) {\n const [low, high] = heatRange(view);\n const ramp = h(\"i\", { class: \"rx-ramp\", \"aria-hidden\": \"true\" }, ...Array.from({ length: HEAT_STEPS }, (_, i) => h(\"b\", { class: `rx-s${i}` })));\n parts.push(h(\"span\", { class: \"rx-key\" }, formatValue(low), ramp, formatValue(high)));\n if (panel?.kind === \"surface\") parts.push(item(mark(\"rx-mark-veil\"), \"gray veil: far from the data\"));\n }\n if (panel !== undefined) parts.push(item(mark(\"rx-mark-dot\"), \"measured point\"));\n return h(\"p\", { class: \"rx-legend\" }, ...parts);\n}\n\n/** This function makes a table of numbers. */\nfunction tableOf(view: ExplorerView, panel: ExplorerPanel): HTMLElement {\n const { columns, rows } = numberTable(view, panel);\n const head = h(\"tr\", {}, ...columns.map((column) => h(\"th\", { scope: \"col\" }, column)));\n const body = rows.map((row) => h(\"tr\", {}, ...row.map((cell) => h(\"td\", {}, cell))));\n const table = h(\"table\", { class: \"rx-table\" }, ...(panel.title === \"\" ? [] : [h(\"caption\", {}, panel.title)]), h(\"thead\", {}, head), h(\"tbody\", {}, ...body));\n return table;\n}\n\n/** This function makes a select of dimensions. The first option is the value `none`, if the control has one. */\nfunction dimensionSelect(label: string, key: string, choices: readonly DimensionChoice[], value: string | null, none: string | null, change: (id: string | null) => void): HTMLElement {\n const options = choices.map((choice) => {\n const text = choice.disabled ? `${choice.label}: ${choice.reason}` : choice.label;\n return h(\"option\", { value: choice.id, disabled: choice.disabled, selected: choice.id === value }, text);\n });\n const select = h(\"select\", { \"data-key\": key }, ...(none === null ? [] : [h(\"option\", { value: \"\", selected: value === null }, none)]), ...options);\n select.addEventListener(\"change\", () => change(select.value === \"\" ? null : select.value));\n return h(\"label\", { class: \"rx-field\" }, h(\"span\", {}, label), select);\n}\n\n/** The fields of a level in a group. */\ninterface LevelOption {\n readonly text: string;\n readonly checked: boolean;\n readonly disabled: boolean;\n readonly reason: string;\n readonly choose: () => void;\n}\n\n/** This function makes a select of levels. A closed select shows the held value and takes one row. */\nfunction levelSelect(label: string, key: string, options: readonly LevelOption[], note: string): HTMLElement {\n const items = options.map((option, i) => {\n const text = option.disabled ? `${option.text}: ${option.reason}` : option.text;\n return h(\"option\", { value: i, disabled: option.disabled, selected: option.checked }, text);\n });\n const select = h(\"select\", { \"data-key\": key }, ...items);\n select.addEventListener(\"change\", () => options[Number(select.value)]?.choose());\n const field = h(\"label\", { class: \"rx-field\" }, h(\"span\", {}, label), select);\n return h(\"div\", { class: \"rx-hold\" }, field, note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, note));\n}\n\n/** This function makes a group of levels. Level buttons are radio inputs, so the keyboard works with no script. */\nfunction levelGroup(label: string, key: string, name: string, options: readonly LevelOption[], note: string): HTMLElement {\n if (levelForm(options.length) === \"select\") return levelSelect(label, key, options, note);\n const chips = options.map((option, i) => {\n const input = h(\"input\", { class: \"rx-radio\", type: \"radio\", name, checked: option.checked, disabled: option.disabled, \"data-key\": `${key}:${i}` });\n input.addEventListener(\"change\", option.choose);\n return h(\"label\", { class: \"rx-chip\", title: option.reason === \"\" ? undefined : option.reason }, input, h(\"span\", {}, option.text));\n });\n const legend = h(\"legend\", { class: \"rx-name\" }, label);\n return h(\"fieldset\", { class: \"rx-hold\" }, legend, h(\"div\", { class: \"rx-chips\" }, ...chips), note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, note));\n}\n\n/** This function makes a slider over the values of a held dimension. */\nfunction stopSlider(control: HoldControl, key: string, change: (value: ResponseValue) => void): HTMLElement {\n const values = control.options.map((option) => option.value);\n const index = Math.max(0, values.indexOf(control.value));\n const output = h(\"output\", { class: \"rx-value\" }, formatValue(control.value));\n const input = h(\"input\", { class: \"rx-slider\", type: \"range\", min: 0, max: values.length - 1, step: 1, value: index, disabled: !control.applies, \"data-key\": key, \"aria-label\": control.label, \"aria-valuetext\": formatValue(control.value) });\n input.addEventListener(\"input\", () => {\n const value = values[Number(input.value)] as ResponseValue;\n output.textContent = formatValue(value);\n input.setAttribute(\"aria-valuetext\", formatValue(value));\n change(value);\n });\n const head = h(\"div\", { class: \"rx-slider-head\" }, h(\"span\", { class: \"rx-name\" }, control.label), output);\n return h(\"div\", { class: \"rx-hold\" }, head, input, control.note === \"\" ? null : h(\"p\", { class: \"rx-note\" }, control.note));\n}\n\n/** This function shows each fault of a bad record, with its path. */\nfunction faultView(faults: readonly { readonly path: string; readonly message: string }[]): HTMLElement {\n const items = faults.slice(0, MAX_FAULTS).map((fault) => h(\"li\", {}, h(\"code\", {}, fault.path === \"\" ? \"(the record)\" : fault.path), ` ${fault.message}`));\n const more = faults.length > MAX_FAULTS ? h(\"p\", {}, `The list shows ${MAX_FAULTS} of ${faults.length} faults.`) : null;\n const title = faults.length === 1 ? \"This record has 1 fault.\" : `This record has ${faults.length} faults.`;\n return h(\"div\", { class: \"rx-faults\", role: \"alert\" }, h(\"p\", { class: \"rx-faults-title\" }, title), h(\"ul\", {}, ...items), more);\n}\n\n/**\n * This function shows a record of the format `response-records/1` in a host element. It reads the record only with\n * `parseResponseRecord`. A bad record shows its faults with their paths, and the function does not throw.\n *\n * @param host - The element of the explorer. The function replaces its children.\n * @param recordJson - The record as JSON text, or as parsed data.\n * @param options - The first state, the time of a surface and the clock.\n */\nexport function mountExplorer(host: HTMLElement, recordJson: unknown, options: ExplorerOptions = {}): ExplorerHandle {\n const parsed = openRecord(recordJson);\n if (!parsed.ok) {\n host.replaceChildren(h(\"div\", { class: \"response-explorer\" }, faultView(parsed.faults)));\n return { state: () => null, destroy: () => host.replaceChildren() };\n }\n return mountRecord(host, parsed.record, options);\n}\n\n/** This function connects a good record to the DOM. */\nfunction mountRecord(host: HTMLElement, record: ResponseRecord, options: ExplorerOptions): ExplorerHandle {\n const { budgetMs = SURFACE_BUDGET_MS, now = (): number => performance.now() } = options;\n const mount = ++mounts;\n let state = settle(record, options.initial);\n let cap = MAX_STEPS;\n let frame = 0;\n let drawnWidth = 0;\n let view: ExplorerView | undefined;\n\n const controls = h(\"div\", { class: \"rx-controls\" });\n const panels = h(\"div\", { class: \"rx-panels\" });\n const error = h(\"p\", { class: \"rx-error\" });\n const model = h(\"p\", { class: \"rx-note\" });\n const legend = h(\"div\", { class: \"rx-legend-box\" });\n const readout = h(\"p\", { class: \"rx-readout\", \"aria-live\": \"polite\" });\n const numbers = h(\"div\", { class: \"rx-numbers-body\" });\n const details = h(\"details\", { class: \"rx-numbers\" }, h(\"summary\", {}, \"Show the numbers\"), numbers);\n const chart = h(\"div\", { class: \"rx-chart\" }, error, panels, legend, readout, model, details);\n const root = h(\"div\", { class: \"response-explorer\" }, controls, chart);\n\n const tell = (text: string): void => {\n readout.textContent = text;\n };\n\n /** This function fills the table when the visitor opens it, so a closed table costs no time. */\n const drawNumbers = (): void => {\n numbers.replaceChildren(...(details.open && view !== undefined ? view.panels.map((panel) => h(\"div\", { class: \"rx-table-box scroll-cue\" }, tableOf(view as ExplorerView, panel))) : []));\n };\n\n /** This function draws the charts of the last view at the width of the host. */\n const drawCharts = (): void => {\n const current = view;\n if (current === undefined) return;\n const single = current.panels.length === 1;\n const available = panels.clientWidth > 0 ? panels.clientWidth : FALLBACK_WIDTH;\n const columns = single ? 1 : Math.min(current.panels.length, Math.max(1, Math.floor((available + 12) / 272)));\n const width = Math.floor((available - (columns - 1) * 12) / columns);\n drawnWidth = available;\n panels.replaceChildren(\n ...current.panels.map((panel, i) => {\n const title = panel.title === \"\" ? null : h(\"figcaption\", { class: \"rx-panel-title\" }, panel.title);\n const chartBox = panelChart(current, panel, width, `rx-band-${mount}-${i}`, tell);\n return h(\"figure\", { class: \"rx-panel\" }, title, chartBox, h(\"p\", { class: \"rx-note\" }, pointsText(panel)));\n }),\n );\n };\n\n /** This function asks the core for a view, and it draws the view. */\n const drawView = (): void => {\n const next = viewOf(record, state, { stepsCap: cap, budgetMs, now });\n view = next;\n cap = next.nextCap;\n if (next.problem !== \"\") {\n error.textContent = `The record refused this view: ${next.problem}`;\n } else {\n const head = next.error === null ? null : h(\"strong\", {}, \"Held-out error. \");\n error.replaceChildren(...(head === null ? [] : [head]), next.errorText);\n }\n model.textContent = [next.modelText, next.gridText, next.rangeText].filter((text) => text !== \"\").join(\" \");\n legend.replaceChildren(legendOf(next));\n tell(\"Move over a chart, or focus it and use the arrow keys.\");\n drawCharts();\n drawNumbers();\n };\n\n /** This function draws at the next frame. A slider gives many events in one frame. */\n const later = (): void => {\n if (frame !== 0) return;\n frame = requestAnimationFrame(() => {\n frame = 0;\n drawView();\n });\n };\n\n /** This function makes the controls of the state again, and it keeps the focus on the same control. */\n const drawControls = (): void => {\n const focused = document.activeElement instanceof HTMLElement ? document.activeElement.dataset[\"key\"] : undefined;\n const update = (next: ExplorerState): void => {\n state = next;\n drawControls();\n drawView();\n };\n const measures = levelGroup(\n \"Measure\",\n \"measure\",\n `rx-measure-${mount}`,\n record.measures.map((m) => ({ text: m.label, checked: m.id === state.measure, disabled: false, reason: \"\", choose: () => update(setMeasure(record, state, m.id)) })),\n \"\",\n );\n const axes = h(\n \"div\",\n { class: \"rx-axes\" },\n dimensionSelect(\"Across\", \"x\", axisChoices(record, state, \"x\"), state.x, null, (id) => update(setAxis(record, state, \"x\", id))),\n dimensionSelect(\"Up\", \"y\", axisChoices(record, state, \"y\"), state.y, \"None (a curve)\", (id) => update(setAxis(record, state, \"y\", id))),\n dimensionSelect(\"Panels\", \"facet\", facetChoices(record, state), state.facet, \"One panel\", (id) => update(setFacet(record, state, id))),\n );\n const holds = holdControls(record, state).map((control) => {\n if (control.kind === \"stops\") {\n return stopSlider(control, `hold:${control.id}`, (value) => {\n state = setHold(record, state, control.id, value);\n later();\n });\n }\n const levels = control.options.map((option) => ({ text: option.text, checked: option.value === control.value, disabled: option.disabled, reason: option.reason, choose: () => update(setHold(record, state, control.id, option.value)) }));\n return levelGroup(control.label, `hold:${control.id}`, `rx-${mount}-${control.id}`, levels, control.note);\n });\n const held = holds.length === 0 ? [] : [h(\"p\", { class: \"rx-section\" }, \"Held values\"), ...holds];\n controls.replaceChildren(measures, axes, ...held);\n if (focused !== undefined) {\n const keyed = [...controls.querySelectorAll<HTMLElement>(\"[data-key]\")].find((el) => el.dataset[\"key\"] === focused);\n keyed?.focus();\n }\n };\n\n details.addEventListener(\"toggle\", drawNumbers);\n host.replaceChildren(root);\n drawControls();\n drawView();\n\n const observer =\n typeof ResizeObserver === \"undefined\"\n ? undefined\n : new ResizeObserver(() => {\n if (panels.clientWidth > 0 && Math.abs(panels.clientWidth - drawnWidth) > 1) drawCharts();\n });\n observer?.observe(panels);\n\n return {\n state: () => state,\n destroy: () => {\n observer?.disconnect();\n if (frame !== 0) cancelAnimationFrame(frame);\n host.replaceChildren();\n },\n };\n}\n"],"mappings":"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"}
|
package/build/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as CheckState, B as OpenWorkTotals, C as kpiProblems, D as BoardIssue, E as writeKpi, F as KpiFile, G as StatusClass, H as ReleaseChange, I as KpiMeasure, L as Link, M as GitHubRelease, N as GitHubReleases, O as BoardItem, P as KpiEngine, R as NpmPublishTimes, S as kpiFile, T as readKpi, U as ReleaseKind, V as Release, W as StatusBoardData, _ as parseDataStamps, a as DataStamps, b as KpiError, c as FreshnessOptions, d as MAX_MINORS_BEHIND, f as PageStamp, g as minorsBehind, h as latestAt, i as DataRun, j as GitHubOpenWork, k as BoardPullRequest, l as MAX_DATA_AGE_DAYS, m as cronLines, n as DATA_STAMP_SCHEMA, o as DataStampsParse, p as checkFreshness, r as DataLimit, s as FreshnessCheck, t as CronLine, u as MAX_LIMIT_DAYS_WITHOUT_RULING, v as KPI_FILE, w as kpiText, x as KpiInput, y as KPI_FORMAT, z as NpmVersionTime } from "./chunks/freshness.js";
|
|
2
2
|
/** The parts of a SemVer 2.0.0 version. */
|
|
3
3
|
interface ParsedVersion {
|
|
4
4
|
major: number;
|
|
@@ -586,5 +586,5 @@ export declare function parseBuildArgs(argv: readonly string[], io: Pick<CliIo,
|
|
|
586
586
|
* source is not correct, and 2 for an incorrect command line.
|
|
587
587
|
*/
|
|
588
588
|
export declare function runCli(argv: readonly string[], io: CliIo): Promise<number>;
|
|
589
|
-
export { type BoardIssue, type BoardItem, type BoardPullRequest, type BoardSection, type BuildOptions, type BuildResult, type ChangelogEntry, type ChangelogSection, type ChangelogSource, type CheckState, type CliIo, DATA_STAMP_SCHEMA, type DataLimit, type DataRun, type DataStamps, type DataStampsParse, type FreshnessCheck, type FreshnessOptions, type GitHubOpenWork, type GitHubOptions, type GitHubRelease, type GitHubReleases, type ItemGroup, KPI_FILE, KPI_FORMAT, type KpiEngine, KpiError, type KpiFile, type KpiInput, type KpiMeasure, type Link, type LinkOptions, MAX_DATA_AGE_DAYS, MAX_LIMIT_DAYS_WITHOUT_RULING, MAX_MINORS_BEHIND, type MarkdownTable, type NpmOptions, type NpmPublishTimes, type NpmVersionTime, type OpenWorkTotals, type PageOptions, type PageParts, type PageStamp, type ParsedVersion, type ReadReleasesOptions, type ReadStatusBoardOptions, type Release, type ReleaseChange, type ReleaseKind, type ReleasePoint, type ReleaseSources, type ReleaseSummary, type StatusBoardData, type StatusBoardInput, type StatusClass, type TagDate, type TagVersion, type TimelineBand, type TimelineLayout, type TimelineMark, type TimelineOptions, checkFreshness, kpiFile, kpiProblems, kpiText, latestAt, minorsBehind, parseDataStamps, readKpi, writeKpi };
|
|
589
|
+
export { type BoardIssue, type BoardItem, type BoardPullRequest, type BoardSection, type BuildOptions, type BuildResult, type ChangelogEntry, type ChangelogSection, type ChangelogSource, type CheckState, type CliIo, type CronLine, DATA_STAMP_SCHEMA, type DataLimit, type DataRun, type DataStamps, type DataStampsParse, type FreshnessCheck, type FreshnessOptions, type GitHubOpenWork, type GitHubOptions, type GitHubRelease, type GitHubReleases, type ItemGroup, KPI_FILE, KPI_FORMAT, type KpiEngine, KpiError, type KpiFile, type KpiInput, type KpiMeasure, type Link, type LinkOptions, MAX_DATA_AGE_DAYS, MAX_LIMIT_DAYS_WITHOUT_RULING, MAX_MINORS_BEHIND, type MarkdownTable, type NpmOptions, type NpmPublishTimes, type NpmVersionTime, type OpenWorkTotals, type PageOptions, type PageParts, type PageStamp, type ParsedVersion, type ReadReleasesOptions, type ReadStatusBoardOptions, type Release, type ReleaseChange, type ReleaseKind, type ReleasePoint, type ReleaseSources, type ReleaseSummary, type StatusBoardData, type StatusBoardInput, type StatusClass, type TagDate, type TagVersion, type TimelineBand, type TimelineLayout, type TimelineMark, type TimelineOptions, checkFreshness, cronLines, kpiFile, kpiProblems, kpiText, latestAt, minorsBehind, parseDataStamps, readKpi, writeKpi };
|
|
590
590
|
//# sourceMappingURL=index.d.ts.map
|
package/build/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as NPM_REGISTRY, C as readKpi, D as headingDate, E as headCommit, F as versionOfTag, M as compareVersions, N as kindOf, O as isShallow, P as parseVersion, S as kpiText, T as gitTagDates, _ as KPI_FILE, a as checkFreshness, b as kpiFile, c as minorsBehind, d as escapeHtml, f as inlineMarkdown, g as safeUrl, i as MAX_MINORS_BEHIND, j as npmPublishTimes, k as originRepository, l as parseDataStamps, n as MAX_DATA_AGE_DAYS, o as cronLines, r as MAX_LIMIT_DAYS_WITHOUT_RULING, s as latestAt, t as DATA_STAMP_SCHEMA, v as KPI_FORMAT, w as writeKpi, x as kpiProblems, y as KpiError } from "./chunks/freshness.js";
|
|
2
2
|
import { $ as parseChangelog, A as STATUS_CLASSES, B as DEFAULT_CHANGELOGS, C as pageShell, D as utcDay, E as shortDate, F as plainText, G as globFiles, H as mergeReleases, I as readStatusBoard, J as checkStateOf, K as GITHUB_API, L as roadmapItems, M as linksOf, N as markdownTables, O as OPEN_CLASSES, P as parseRoadmap, Q as headingAnchor, R as splitRow, S as BASE_CSS, T as longDate, U as readChangelogs, V as ReleaseDataError, W as readReleases, X as githubReleases, Y as githubOpenWork, Z as firstSentence, _ as renderReleasesPage, a as runCli, b as releaseSummary, c as STATUS_SCRIPT, d as renderStatusPage, et as releaseBodyEntries, f as sectionsOf, g as releasesLead, h as RELEASES_SCRIPT, i as parseBuildArgs, j as buildStatusBoard, k as RoadmapParseError, l as classCounts, m as statusLead, n as UsageError, o as TYPESCRIPT_PROBE, p as slugOf, q as GITHUB_GRAPHQL, r as build, s as probeScript, t as HELP, u as openGroups, v as laneCenter, w as dayRange, x as timelineLayout, y as oldestFirst, z as statusClassOf } from "./chunks/build.js";
|
|
3
3
|
import { t as renderDataStamp } from "./chunks/data-stamp.js";
|
|
4
|
-
export { BASE_CSS, DATA_STAMP_SCHEMA, DEFAULT_CHANGELOGS, GITHUB_API, GITHUB_GRAPHQL, HELP, KPI_FILE, KPI_FORMAT, KpiError, MAX_DATA_AGE_DAYS, MAX_LIMIT_DAYS_WITHOUT_RULING, MAX_MINORS_BEHIND, NPM_REGISTRY, OPEN_CLASSES, RELEASES_SCRIPT, ReleaseDataError, RoadmapParseError, STATUS_CLASSES, STATUS_SCRIPT, TYPESCRIPT_PROBE, UsageError, build, buildStatusBoard, checkFreshness, checkStateOf, classCounts, compareVersions, dayRange, escapeHtml, firstSentence, gitTagDates, githubOpenWork, githubReleases, globFiles, headCommit, headingAnchor, headingDate, inlineMarkdown, isShallow, kindOf, kpiFile, kpiProblems, kpiText, laneCenter, latestAt, linksOf, longDate, markdownTables, mergeReleases, minorsBehind, npmPublishTimes, oldestFirst, openGroups, originRepository, pageShell, parseBuildArgs, parseChangelog, parseDataStamps, parseRoadmap, parseVersion, plainText, probeScript, readChangelogs, readKpi, readReleases, readStatusBoard, releaseBodyEntries, releaseSummary, releasesLead, renderDataStamp, renderReleasesPage, renderStatusPage, roadmapItems, runCli, safeUrl, sectionsOf, shortDate, slugOf, splitRow, statusClassOf, statusLead, timelineLayout, utcDay, versionOfTag, writeKpi };
|
|
4
|
+
export { BASE_CSS, DATA_STAMP_SCHEMA, DEFAULT_CHANGELOGS, GITHUB_API, GITHUB_GRAPHQL, HELP, KPI_FILE, KPI_FORMAT, KpiError, MAX_DATA_AGE_DAYS, MAX_LIMIT_DAYS_WITHOUT_RULING, MAX_MINORS_BEHIND, NPM_REGISTRY, OPEN_CLASSES, RELEASES_SCRIPT, ReleaseDataError, RoadmapParseError, STATUS_CLASSES, STATUS_SCRIPT, TYPESCRIPT_PROBE, UsageError, build, buildStatusBoard, checkFreshness, checkStateOf, classCounts, compareVersions, cronLines, dayRange, escapeHtml, firstSentence, gitTagDates, githubOpenWork, githubReleases, globFiles, headCommit, headingAnchor, headingDate, inlineMarkdown, isShallow, kindOf, kpiFile, kpiProblems, kpiText, laneCenter, latestAt, linksOf, longDate, markdownTables, mergeReleases, minorsBehind, npmPublishTimes, oldestFirst, openGroups, originRepository, pageShell, parseBuildArgs, parseChangelog, parseDataStamps, parseRoadmap, parseVersion, plainText, probeScript, readChangelogs, readKpi, readReleases, readStatusBoard, releaseBodyEntries, releaseSummary, releasesLead, renderDataStamp, renderReleasesPage, renderStatusPage, roadmapItems, runCli, safeUrl, sectionsOf, shortDate, slugOf, splitRow, statusClassOf, statusLead, timelineLayout, utcDay, versionOfTag, writeKpi };
|
package/build/vite.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BuildInfo } from "./chrome.js";
|
|
2
|
-
import {
|
|
2
|
+
import { a as DataStamps, x as KpiInput } from "./chunks/freshness.js";
|
|
3
3
|
/** The environment variables that this module reads. */
|
|
4
4
|
export type SiteEnv = Readonly<Record<string, string | undefined>>;
|
|
5
5
|
/** The options of `siteShell`. */
|
package/build/vite.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { E as headCommit, S as kpiText, _ as KPI_FILE, b as kpiFile, l as parseDataStamps } from "./chunks/freshness.js";
|
|
2
2
|
import { t as renderDataStamp } from "./chunks/data-stamp.js";
|
|
3
3
|
import { readFileSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
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.2.
|
|
4
|
+
"version": "0.2.12",
|
|
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",
|