Files
tech-log-frontend/scripts/check-optional-recipe-types.ts
T

63 lines
1.6 KiB
TypeScript

import { spawnSync } from "node:child_process";
import { readdir } from "node:fs/promises";
import { extname, resolve } from "node:path";
const recipeRoot = resolve("recipes");
const pnpmCli = requireEnvironment("npm_execpath");
if (!(await containsTypeScriptSource(recipeRoot))) {
process.stdout.write(
"Optional recipe typecheck: SKIP (no recipe TypeScript sources installed)\n",
);
} else {
const result = spawnSync(
process.execPath,
[pnpmCli, "exec", "tsc", "--project", "tsconfig.recipes.json"],
{ stdio: "inherit" },
);
if (result.error) {
throw result.error;
}
process.exitCode = result.status ?? 1;
}
function requireEnvironment(name: string): string {
const value = process.env[name];
if (!value) {
throw new Error(`${name} is required to typecheck optional recipes`);
}
return value;
}
async function containsTypeScriptSource(directory: string): Promise<boolean> {
let entries;
try {
entries = await readdir(directory, { withFileTypes: true });
} catch (error) {
if (hasErrorCode(error, "ENOENT")) {
return false;
}
throw error;
}
for (const entry of entries) {
const target = resolve(directory, entry.name);
if (entry.isDirectory() && (await containsTypeScriptSource(target))) {
return true;
}
if (entry.isFile() && [".ts", ".tsx", ".mts", ".cts"].includes(extname(entry.name))) {
return true;
}
}
return false;
}
function hasErrorCode(error: unknown, code: string): boolean {
return (
typeof error === "object" &&
error !== null &&
"code" in error &&
error.code === code
);
}