63 lines
2.1 KiB
JavaScript
63 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { existsSync, readFileSync, readdirSync } from "node:fs";
|
|
import { join } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const ROOT = join(import.meta.dirname, "..");
|
|
export const REQUIRED_WORKSPACE_SCRIPTS = ["build", "typecheck", "test"];
|
|
|
|
function hasExecutableScript(pkg, script) {
|
|
return typeof pkg.scripts?.[script] === "string" && pkg.scripts[script].trim().length > 0;
|
|
}
|
|
|
|
function hasSpecificReason(reason) {
|
|
return typeof reason === "string" ? reason.trim().length >= 20 : false;
|
|
}
|
|
|
|
function hasDocumentedOptOut(pkg, script) {
|
|
const optOut = pkg.hyperframesWorkspaceContract?.[script];
|
|
return optOut?.optOut === true && hasSpecificReason(optOut.reason);
|
|
}
|
|
|
|
export function listWorkspaceContractIssues(workspace, pkg) {
|
|
return REQUIRED_WORKSPACE_SCRIPTS.flatMap((script) => {
|
|
if (hasExecutableScript(pkg, script) || hasDocumentedOptOut(pkg, script)) return [];
|
|
return [
|
|
`${workspace}: missing executable \`${script}\` script or ` +
|
|
`hyperframesWorkspaceContract.${script} opt-out with a specific reason`,
|
|
];
|
|
});
|
|
}
|
|
|
|
export function listWorkspacePackages(root = ROOT) {
|
|
const packagesDir = join(root, "packages");
|
|
return readdirSync(packagesDir)
|
|
.sort()
|
|
.filter((name) => existsSync(join(packagesDir, name, "package.json")))
|
|
.map((name) => {
|
|
const workspace = `packages/${name}`;
|
|
const pkg = JSON.parse(readFileSync(join(root, workspace, "package.json"), "utf8"));
|
|
return { workspace, pkg };
|
|
});
|
|
}
|
|
|
|
export function checkWorkspaceContracts(root = ROOT) {
|
|
return listWorkspacePackages(root).flatMap(({ workspace, pkg }) =>
|
|
listWorkspaceContractIssues(workspace, pkg),
|
|
);
|
|
}
|
|
|
|
function main() {
|
|
const issues = checkWorkspaceContracts();
|
|
if (issues.length > 0) {
|
|
console.error("Workspace contract violations:");
|
|
issues.forEach((issue) => console.error(`- ${issue}`));
|
|
process.exitCode = 1;
|
|
return;
|
|
}
|
|
console.log("Workspace contracts verified: build, typecheck, and test are explicit.");
|
|
}
|
|
|
|
if (process.argv[1] === fileURLToPath(import.meta.url)) main();
|