68 lines
2.4 KiB
JavaScript
68 lines
2.4 KiB
JavaScript
import { execFile } from "node:child_process";
|
|
import { createHash } from "node:crypto";
|
|
import { mkdtemp, readFile, readdir, rm } from "node:fs/promises";
|
|
import { tmpdir } from "node:os";
|
|
import { dirname, join, relative } from "node:path";
|
|
import { promisify } from "node:util";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const execFileAsync = promisify(execFile);
|
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const temporaryRoot = await mkdtemp(join(tmpdir(), "rea-typedoc-check-"));
|
|
const generated = join(temporaryRoot, "api");
|
|
|
|
const files = async (directory) =>
|
|
(await readdir(directory, { recursive: true, withFileTypes: true }))
|
|
.filter((entry) => entry.isFile())
|
|
.map((entry) => relative(directory, join(entry.parentPath, entry.name)))
|
|
.sort();
|
|
const digest = async (path) =>
|
|
createHash("sha256")
|
|
.update(await readFile(path))
|
|
.digest("hex");
|
|
|
|
try {
|
|
const { stderr } = await execFileAsync(
|
|
process.execPath,
|
|
[join(root, "node_modules/typedoc/bin/typedoc"), "--out", generated],
|
|
{ cwd: root, maxBuffer: 4 * 1024 * 1024 },
|
|
);
|
|
if (stderr.trim().length > 0) process.stderr.write(stderr);
|
|
const committed = join(root, "docs/api");
|
|
const [expectedFiles, actualFiles] = await Promise.all([
|
|
files(generated),
|
|
files(committed),
|
|
]);
|
|
const expectedSet = new Set(expectedFiles);
|
|
const actualSet = new Set(actualFiles);
|
|
const missing = expectedFiles.filter((path) => !actualSet.has(path));
|
|
const extra = actualFiles.filter((path) => !expectedSet.has(path));
|
|
const common = expectedFiles.filter((path) => actualSet.has(path));
|
|
const changed = (
|
|
await Promise.all(
|
|
common.map(async (path) =>
|
|
(await digest(join(generated, path))) ===
|
|
(await digest(join(committed, path)))
|
|
? undefined
|
|
: path,
|
|
),
|
|
)
|
|
).filter((path) => path !== undefined);
|
|
if (missing.length > 0 || extra.length > 0 || changed.length > 0) {
|
|
const summarize = (label, paths) =>
|
|
paths.length === 0
|
|
? []
|
|
: [`${label}:`, ...paths.slice(0, 20).map((path) => ` ${path}`)];
|
|
throw new Error(
|
|
[
|
|
"Committed TypeDoc output is stale. Run `npm run docs:generate`.",
|
|
...summarize("Missing", missing),
|
|
...summarize("Extra", extra),
|
|
...summarize("Changed", changed),
|
|
].join("\n"),
|
|
);
|
|
}
|
|
} finally {
|
|
await rm(temporaryRoot, { recursive: true, force: true });
|
|
}
|