@mark1russell7/site-pages 0.2.2 → 0.2.3
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/README.md +30 -0
- package/build/{build-xJqNIzdO.js → chunks/build.js} +24 -67
- package/build/chunks/build.js.map +1 -0
- package/build/chunks/kpi.d.ts +212 -0
- package/build/chunks/kpi.d.ts.map +1 -0
- package/build/chunks/kpi.js +222 -0
- package/build/chunks/kpi.js.map +1 -0
- package/build/cli.js +1 -1
- package/build/index.d.ts +5 -147
- package/build/index.d.ts.map +1 -1
- package/build/index.js +3 -1
- package/build/vite.d.ts +26 -0
- package/build/vite.d.ts.map +1 -1
- package/build/vite.js +26 -1
- package/build/vite.js.map +1 -1
- package/package.json +1 -1
- package/build/build-xJqNIzdO.js.map +0 -1
package/README.md
CHANGED
|
@@ -368,6 +368,36 @@ The theme `auto` removes `data-theme`, and the CSS of the site then obeys `prefe
|
|
|
368
368
|
</script>
|
|
369
369
|
```
|
|
370
370
|
|
|
371
|
+
## The measures of a site
|
|
372
|
+
|
|
373
|
+
The file `kpi.json` at the root of a site holds the measures of the project, in the format `kpi/1`. A reader outside the site takes the numbers from this file.
|
|
374
|
+
|
|
375
|
+
```ts
|
|
376
|
+
import { defineConfig } from "vite";
|
|
377
|
+
import { siteKpi } from "@mark1russell7/site-pages/vite";
|
|
378
|
+
|
|
379
|
+
export default defineConfig({
|
|
380
|
+
plugins: [siteKpi({ project: "acme", at: data.at, measures: [{ id: "cases", value: data.cases.length, unit: "cases" }] })],
|
|
381
|
+
});
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
```ts
|
|
385
|
+
interface KpiFile {
|
|
386
|
+
format: "kpi/1";
|
|
387
|
+
project: string;
|
|
388
|
+
at: string; // the ISO time of the data in UTC, never the time of the build
|
|
389
|
+
commit: string; // the full commit of the build
|
|
390
|
+
measures: Array<{ id: string; value: number; unit?: string }>;
|
|
391
|
+
engines?: Array<{ name: string; version: string }>; // the Status page shows them
|
|
392
|
+
}
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
- Give `at` from the record of the data. The writer has no default for this field, because a build time hides old data.
|
|
396
|
+
- Without `commit`, the plugin takes `GITHUB_SHA`, else the head of the repository.
|
|
397
|
+
- A fault in the data stops the build, and the old site stays. A fault is a wrong form, a value that is not finite, a repeated id or a time after the check.
|
|
398
|
+
- A site with no Vite build calls `writeKpi(out, input)` from the root entry, before `site-pages build`.
|
|
399
|
+
- `site-pages build` reads the file from the output folder. It adds the file to `data/status.json`, and the Status page shows the measures, the data date and the engines.
|
|
400
|
+
|
|
371
401
|
## The shell of a site
|
|
372
402
|
|
|
373
403
|
The shell is the part of a page that is not its content. The package has two parts of the shell, and each part is optional.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { d as headingDate, f as isShallow, l as gitTagDates, p as originRepository, r as KpiError, s as readKpi, t as KPI_FILE, u as headCommit } from "./kpi.js";
|
|
1
2
|
import { stripTypeScriptTypes } from "node:module";
|
|
2
|
-
import { execFileSync } from "node:child_process";
|
|
3
3
|
import { existsSync, mkdirSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
4
4
|
import { basename, dirname, isAbsolute, join, posix, resolve } from "node:path";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
@@ -496,65 +496,6 @@ async function npmPublishTimes(options) {
|
|
|
496
496
|
problems
|
|
497
497
|
};
|
|
498
498
|
}
|
|
499
|
-
// src/data/git.ts
|
|
500
|
-
/**
|
|
501
|
-
* The git source: the tags with their dates, the commit of the build and the GitHub remote. Each
|
|
502
|
-
* function gives an empty result when git or the repository is not available.
|
|
503
|
-
*/
|
|
504
|
-
/** This function starts git in a folder and gives its output, or null when git fails. */
|
|
505
|
-
function git(repoDir, ...args) {
|
|
506
|
-
try {
|
|
507
|
-
return execFileSync("git", args, {
|
|
508
|
-
cwd: repoDir,
|
|
509
|
-
encoding: "utf8",
|
|
510
|
-
stdio: [
|
|
511
|
-
"ignore",
|
|
512
|
-
"pipe",
|
|
513
|
-
"ignore"
|
|
514
|
-
],
|
|
515
|
-
windowsHide: true
|
|
516
|
-
});
|
|
517
|
-
} catch {
|
|
518
|
-
return null;
|
|
519
|
-
}
|
|
520
|
-
}
|
|
521
|
-
/** This function tells if the clone is shallow. A shallow clone has not all the tags and commits. */
|
|
522
|
-
function isShallow(repoDir) {
|
|
523
|
-
return git(repoDir, "rev-parse", "--is-shallow-repository")?.trim() === "true";
|
|
524
|
-
}
|
|
525
|
-
/** This function gives each tag of the repository with its date. An annotated tag has its own date. */
|
|
526
|
-
function gitTagDates(repoDir) {
|
|
527
|
-
const output = git(repoDir, "for-each-ref", "--format=%(refname:strip=2) %(creatordate:iso-strict)", "refs/tags");
|
|
528
|
-
if (!output) return [];
|
|
529
|
-
const tags = [];
|
|
530
|
-
for (const line of output.split(/\r?\n/)) {
|
|
531
|
-
const match = /^(\S+) (\S+)$/.exec(line.trim());
|
|
532
|
-
if (match?.[1] && match[2]) tags.push({
|
|
533
|
-
tag: match[1],
|
|
534
|
-
date: match[2]
|
|
535
|
-
});
|
|
536
|
-
}
|
|
537
|
-
return tags;
|
|
538
|
-
}
|
|
539
|
-
/**
|
|
540
|
-
* This function gives the date of the oldest commit that added a version heading to a changelog,
|
|
541
|
-
* or null. The path of the changelog starts at `repoDir`.
|
|
542
|
-
*/
|
|
543
|
-
function headingDate(repoDir, version, file) {
|
|
544
|
-
const dates = (git(repoDir, "log", "--format=%cI", `-S## ${version}`, "--", file) ?? "").trim().split(/\r?\n/).filter(Boolean);
|
|
545
|
-
return dates[dates.length - 1] ?? null;
|
|
546
|
-
}
|
|
547
|
-
/** This function gives the full SHA of `HEAD`, or null. */
|
|
548
|
-
function headCommit(repoDir) {
|
|
549
|
-
const sha = git(repoDir, "rev-parse", "HEAD")?.trim();
|
|
550
|
-
return sha && /^[0-9a-f]{40}$/.test(sha) ? sha : null;
|
|
551
|
-
}
|
|
552
|
-
/** This function gives "owner/name" of the GitHub remote "origin", or null. */
|
|
553
|
-
function originRepository(repoDir) {
|
|
554
|
-
const url = git(repoDir, "remote", "get-url", "origin")?.trim() ?? "";
|
|
555
|
-
const match = /github\.com[:/]([^/]+)\/(.+?)(?:\.git)?\/?$/.exec(url);
|
|
556
|
-
return match ? `${match[1]}/${match[2]}` : null;
|
|
557
|
-
}
|
|
558
499
|
// src/data/glob.ts
|
|
559
500
|
/**
|
|
560
501
|
* A small glob for the changelog files. The syntax has `*` and `?` in one path segment, and `**` for
|
|
@@ -2197,6 +2138,15 @@ function openWork(data) {
|
|
|
2197
2138
|
const doneList = done.length === 0 ? `<p class="sp-done sp-small"><span aria-hidden="true">✓</span> No item is done.</p>` : `<details class="sp-done sp-c-done" data-sp-done><summary><span aria-hidden="true">✓</span> ${doneText} <span data-sp-done-label>Show the done items</span></summary><section class="sp-group sp-c-done" data-sp-group data-class="done" aria-label="The done items">${itemTable(done, data, columns)}<p class="sp-callout" data-sp-done-empty hidden>No done item matches the filters.</p></section></details>`;
|
|
2198
2139
|
return `<section class="sp-section" aria-labelledby="open-work" data-sp-board><h2 id="open-work">Open work</h2><p class="sp-small sp-muted">Each row of a table of ${link(roadmapUrl(data), `<code>${escapeHtml(file)}</code>`)} with an ID and a status that is not done. The build reads the file, so this list follows each commit.</p>` + meter(items) + (open.length > 0 ? filters : "") + list + doneList + "</section>";
|
|
2199
2140
|
}
|
|
2141
|
+
/** This function renders the measures of `kpi.json`: their values, the date of the data and the engines that made it. */
|
|
2142
|
+
function measures(data) {
|
|
2143
|
+
const { kpi } = data;
|
|
2144
|
+
if (kpi === void 0) return "";
|
|
2145
|
+
const rows = kpi.measures.map((measure) => `<tr><th scope="row">${escapeHtml(measure.id)}</th><td>${measure.value}${measure.unit === void 0 ? "" : ` ${escapeHtml(measure.unit)}`}</td></tr>`).join("");
|
|
2146
|
+
const engines = kpi.engines ?? [];
|
|
2147
|
+
const commit = link(`https://github.com/${data.source.github}/commit/${kpi.commit}`, `<code>${kpi.commit.slice(0, 7)}</code>`);
|
|
2148
|
+
return `<section class="sp-section" aria-labelledby="measures"><h2 id="measures">Measures</h2><p>The data of these numbers is from <time datetime="${escapeHtml(kpi.at)}" data-sp-data-date>${escapeHtml(longDate(kpi.at))}</time>. The build of ${commit} published them.</p>` + (engines.length > 0 ? `<p>The engines of the data: ${listText(engines.map((engine) => `<code>${escapeHtml(engine.name)}</code> ${escapeHtml(engine.version)}`))}.</p>` : "") + `<div class="sp-table-box" tabindex="0" role="region" aria-label="Measures"><table class="sp-table"><thead><tr><th scope="col">Measure</th><th scope="col">Value</th></tr></thead><tbody>${rows}</tbody></table></div></section>`;
|
|
2149
|
+
}
|
|
2200
2150
|
function when(date) {
|
|
2201
2151
|
const text = escapeHtml(longDate(date));
|
|
2202
2152
|
return `<time datetime="${escapeHtml(date)}" title="${text}" data-sp-rel>${text}</time>`;
|
|
@@ -2333,7 +2283,7 @@ function renderStatusPage(data, options) {
|
|
|
2333
2283
|
title: "Status",
|
|
2334
2284
|
description: lead,
|
|
2335
2285
|
current: "status",
|
|
2336
|
-
main: `<h1>Status</h1><p class="sp-lead">${escapeHtml(lead)}</p><p class="sp-small sp-muted">The build reads the roadmap file and GitHub again after each commit and on a schedule.</p>` + (data.source.roadmap ? openWork(data) : "") + pullRequests(data) + issues(data),
|
|
2286
|
+
main: `<h1>Status</h1><p class="sp-lead">${escapeHtml(lead)}</p><p class="sp-small sp-muted">The build reads the roadmap file and GitHub again after each commit and on a schedule.</p>` + measures(data) + (data.source.roadmap ? openWork(data) : "") + pullRequests(data) + issues(data),
|
|
2337
2287
|
script: STATUS_SCRIPT
|
|
2338
2288
|
}, options);
|
|
2339
2289
|
}
|
|
@@ -2366,9 +2316,10 @@ function write(file, content, files) {
|
|
|
2366
2316
|
}
|
|
2367
2317
|
/**
|
|
2368
2318
|
* This function reads the sources and writes `data/releases.json`, `data/status.json`,
|
|
2369
|
-
* `releases/index.html` and `status/index.html` into the output folder.
|
|
2319
|
+
* `releases/index.html` and `status/index.html` into the output folder. When the output folder has a
|
|
2320
|
+
* `kpi.json`, the status data and the status page show it.
|
|
2370
2321
|
*
|
|
2371
|
-
* @throws ReleaseDataError or
|
|
2322
|
+
* @throws ReleaseDataError, RoadmapParseError or KpiError when a source on disk is not correct
|
|
2372
2323
|
*/
|
|
2373
2324
|
async function build(options) {
|
|
2374
2325
|
const { repoDir, repository, warn = () => {} } = options;
|
|
@@ -2389,7 +2340,9 @@ async function build(options) {
|
|
|
2389
2340
|
warn,
|
|
2390
2341
|
...fetcher
|
|
2391
2342
|
});
|
|
2392
|
-
const
|
|
2343
|
+
const kpiPath = join(out, KPI_FILE);
|
|
2344
|
+
const kpi = existsSync(kpiPath) ? readKpi(readFileSync(kpiPath, "utf8"), Date.parse(now)) : void 0;
|
|
2345
|
+
const board = await readStatusBoard({
|
|
2393
2346
|
repoDir,
|
|
2394
2347
|
roadmap: options.roadmap ?? null,
|
|
2395
2348
|
owner,
|
|
@@ -2399,6 +2352,10 @@ async function build(options) {
|
|
|
2399
2352
|
generatedAt: now,
|
|
2400
2353
|
...fetcher
|
|
2401
2354
|
});
|
|
2355
|
+
const status = kpi === void 0 ? board : {
|
|
2356
|
+
...board,
|
|
2357
|
+
kpi
|
|
2358
|
+
};
|
|
2402
2359
|
if (!status.github.available) warn(`the status page has no GitHub data: ${status.github.reason ?? "no reason"}.`);
|
|
2403
2360
|
const files = [];
|
|
2404
2361
|
write(join(out, "data", "releases.json"), `${JSON.stringify(releases, null, 2)}\n`, files);
|
|
@@ -2541,13 +2498,13 @@ async function runCli(argv, io) {
|
|
|
2541
2498
|
io.stdout(`site-pages: ${plural(result.releases.length, "release")}, ${plural(result.status.items.length, "roadmap item")} (${open} open), ${github}.\n` + result.files.map((file) => ` ${file}\n`).join(""));
|
|
2542
2499
|
return 0;
|
|
2543
2500
|
} catch (error) {
|
|
2544
|
-
if (error instanceof ReleaseDataError || error instanceof RoadmapParseError || error?.code === "ENOENT") {
|
|
2501
|
+
if (error instanceof ReleaseDataError || error instanceof RoadmapParseError || error instanceof KpiError || error?.code === "ENOENT") {
|
|
2545
2502
|
io.stderr(`site-pages: ${error.message}\n`);
|
|
2546
2503
|
return 1;
|
|
2547
2504
|
}
|
|
2548
2505
|
throw error;
|
|
2549
2506
|
}
|
|
2550
2507
|
}
|
|
2551
|
-
export {
|
|
2508
|
+
export { checkStateOf as $, safeUrl as A, roadmapItems as B, pageShell as C, utcDay as D, shortDate as E, linksOf as F, mergeReleases as G, statusClassOf as H, markdownTables as I, globFiles as J, readChangelogs as K, parseRoadmap as L, RoadmapParseError as M, STATUS_CLASSES as N, escapeHtml as O, buildStatusBoard as P, GITHUB_GRAPHQL as Q, plainText as R, BASE_CSS as S, longDate as T, DEFAULT_CHANGELOGS as U, splitRow as V, ReleaseDataError as W, npmPublishTimes as X, NPM_REGISTRY as Y, GITHUB_API as Z, renderReleasesPage as _, runCli as a, releaseBodyEntries as at, releaseSummary as b, STATUS_SCRIPT as c, parseVersion as ct, renderStatusPage as d, githubOpenWork as et, sectionsOf as f, releasesLead as g, RELEASES_SCRIPT as h, parseBuildArgs as i, parseChangelog as it, OPEN_CLASSES as j, inlineMarkdown as k, classCounts as l, versionOfTag as lt, statusLead as m, UsageError as n, firstSentence as nt, TYPESCRIPT_PROBE as o, compareVersions as ot, slugOf as p, readReleases as q, build as r, headingAnchor as rt, probeScript as s, kindOf as st, HELP as t, githubReleases as tt, openGroups as u, laneCenter as v, dayRange as w, timelineLayout as x, oldestFirst as y, readStatusBoard as z };
|
|
2552
2509
|
|
|
2553
|
-
//# sourceMappingURL=build
|
|
2510
|
+
//# sourceMappingURL=build.js.map
|