Luigit
repositories / pi-ext

pi-ext

bugabingas pi extensions

owned by admin

scripts/lib/common.ts

Raw
import { type SpawnSyncReturns, spawnSync } from "node:child_process";
import { readFileSync, writeFileSync } from "node:fs";
import { dirname, relative, resolve } from "node:path";
import { fileURLToPath } from "node:url";

export const ROOT: string = resolve(
	dirname(fileURLToPath(import.meta.url)),
	"../..",
);

export function readJson(path: string): unknown {
	return JSON.parse(readFileSync(path, "utf8"));
}

export function writeJson(path: string, data: unknown): void {
	writeFileSync(path, `${JSON.stringify(data, null, "\t")}\n`, "utf8");
}

export interface RunOptions {
	cwd?: string;
	capture?: boolean;
	env?: NodeJS.ProcessEnv;
	timeout?: number;
	check?: boolean;
}

export type RunResult = SpawnSyncReturns<string>;

interface RunError extends Error {
	code?: string;
	result?: RunResult;
}

export function run(
	cmd: string,
	args: string[] = [],
	options: RunOptions = {},
): RunResult {
	const result = spawnSync(cmd, args, {
		cwd: options.cwd ?? ROOT,
		encoding: "utf8",
		stdio: options.capture ? ["ignore", "pipe", "pipe"] : "inherit",
		env: options.env ?? process.env,
		timeout: options.timeout,
	});
	if (result.error && (result.error as RunError).code !== "ENOENT")
		throw result.error;
	if (options.check !== false && result.status !== 0) {
		const err = new Error(
			`${cmd} ${args.join(" ")} exited ${result.status ?? result.signal ?? (result.error as RunError | undefined)?.code}`,
		) as RunError;
		err.result = result;
		throw err;
	}
	return result;
}

export function git(args: string[], options: RunOptions = {}): RunResult {
	return run("git", args, { ...options, cwd: ROOT });
}

export function rel(path: string, root: string = ROOT): string {
	return relative(root, path).replaceAll("\\", "/");
}

export function stripAnsi(text: string): string {
	return text
		.replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "")
		.replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "")
		.trim();
}