| import fs from "node:fs"; |
| import path from "node:path"; |
|
|
| export function isTruthy(value: unknown): boolean { |
| if (value === undefined || value === null) { |
| return false; |
| } |
| if (typeof value === "boolean") { |
| return value; |
| } |
| if (typeof value === "number") { |
| return value !== 0; |
| } |
| if (typeof value === "string") { |
| return value.trim().length > 0; |
| } |
| return true; |
| } |
|
|
| export function resolveConfigPath(config: unknown, pathStr: string): unknown { |
| const parts = pathStr.split(".").filter(Boolean); |
| let current: unknown = config; |
| for (const part of parts) { |
| if (typeof current !== "object" || current === null) { |
| return undefined; |
| } |
| current = (current as Record<string, unknown>)[part]; |
| } |
| return current; |
| } |
|
|
| export function isConfigPathTruthyWithDefaults( |
| config: unknown, |
| pathStr: string, |
| defaults: Record<string, boolean>, |
| ): boolean { |
| const value = resolveConfigPath(config, pathStr); |
| if (value === undefined && pathStr in defaults) { |
| return defaults[pathStr] ?? false; |
| } |
| return isTruthy(value); |
| } |
|
|
| export function resolveRuntimePlatform(): string { |
| return process.platform; |
| } |
|
|
| function windowsPathExtensions(): string[] { |
| const raw = process.env.PATHEXT; |
| const list = |
| raw !== undefined ? raw.split(";").map((v) => v.trim()) : [".EXE", ".CMD", ".BAT", ".COM"]; |
| return ["", ...list.filter(Boolean)]; |
| } |
|
|
| let cachedHasBinaryPath: string | undefined; |
| let cachedHasBinaryPathExt: string | undefined; |
| const hasBinaryCache = new Map<string, boolean>(); |
|
|
| export function hasBinary(bin: string): boolean { |
| const pathEnv = process.env.PATH ?? ""; |
| const pathExt = process.platform === "win32" ? (process.env.PATHEXT ?? "") : ""; |
| if (cachedHasBinaryPath !== pathEnv || cachedHasBinaryPathExt !== pathExt) { |
| cachedHasBinaryPath = pathEnv; |
| cachedHasBinaryPathExt = pathExt; |
| hasBinaryCache.clear(); |
| } |
| if (hasBinaryCache.has(bin)) { |
| return hasBinaryCache.get(bin)!; |
| } |
|
|
| const parts = pathEnv.split(path.delimiter).filter(Boolean); |
| const extensions = process.platform === "win32" ? windowsPathExtensions() : [""]; |
| for (const part of parts) { |
| for (const ext of extensions) { |
| const candidate = path.join(part, bin + ext); |
| try { |
| fs.accessSync(candidate, fs.constants.X_OK); |
| hasBinaryCache.set(bin, true); |
| return true; |
| } catch { |
| |
| } |
| } |
| } |
| hasBinaryCache.set(bin, false); |
| return false; |
| } |
|
|