import { spawnSync } from "node:child_process"; import { existsSync, readFileSync, writeFileSync } from "node:fs"; import { dirname, relative, resolve } from "node:path"; import { fileURLToPath } from "node:url"; export const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../.."); export function readJson(path) { return JSON.parse(readFileSync(path, "utf8")); } export function writeJson(path, data) { writeFileSync(path, `${JSON.stringify(data, null, "\t")}\n`, "utf8"); } export function run(cmd, args = [], options = {}) { 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.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?.code}`, ); err.result = result; throw err; } return result; } export function git(args, options = {}) { return run("git", args, { ...options, cwd: ROOT }); } export function commandExists(cmd) { const result = spawnSync(cmd, ["--version"], { stdio: "ignore", timeout: 1000, }); return !result.error; } export function rel(path, root = ROOT) { return relative(root, path).replaceAll("\\", "/"); } export function stripAnsi(text) { return text .replace(/\x1b\][^\x07]*(?:\x07|\x1b\\)/g, "") .replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, "") .trim(); } export function exists(path) { return existsSync(path); }