63 lines
1.6 KiB
TypeScript
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
|
|
);
|
|
}
|