repositories / pi-ext
pi-ext
bugabingas pi extensions
owned by admin
extensions/horst/settings.ts
Raw// horst — settings.
//
// Parses the `horst` block from Pi settings.
export interface HorstSettings {
os: Record<string, string[]>;
hosts: Record<string, string[]>;
preferredShell?: string;
}
export const EMPTY_HORST_SETTINGS: HorstSettings = { os: {}, hosts: {} };
function horstOsKey(platform: string): string | undefined {
if (platform === "linux") return "lnx";
if (platform === "darwin") return "mac";
if (platform === "win32") return "win32";
return undefined;
}
function isObject(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function pickMap(value: unknown, at: string): Record<string, string[]> {
if (value === undefined) return {};
if (!isObject(value)) throw new Error(`${at} must be an object`);
const map: Record<string, string[]> = {};
for (const [key, entry] of Object.entries(value)) {
const tools = isObject(entry) ? entry["tools"] : undefined;
if (!Array.isArray(tools))
throw new Error(
`${at}.${key}.tools must be an array of +name/-name modifiers; use ["+name", "-name"] instead of { add, remove }`,
);
if (
!tools.every(
(tool) =>
typeof tool === "string" &&
(tool.startsWith("+") || tool.startsWith("-")) &&
tool.length > 1 &&
tool === tool.trim() &&
tool.slice(1) === tool.slice(1).trim() &&
!tool.includes("*"),
)
)
throw new Error(
`${at}.${key}.tools must contain only +name/-name modifiers with non-empty exact tool names, not patterns`,
);
map[key.toLowerCase()] = tools;
}
return map;
}
/** Validate the `horst` block; throws on malformed values. */
export function parseHorst(raw: unknown): HorstSettings {
if (!isObject(raw)) throw new Error("expected an object");
const { preferredShell } = raw;
if (
preferredShell !== undefined &&
(typeof preferredShell !== "string" || !preferredShell.trim())
)
throw new Error("preferredShell must be a non-empty string");
return {
os: pickMap(raw["os"], "os"),
hosts: pickMap(raw["hosts"], "hosts"),
...(preferredShell ? { preferredShell: preferredShell.trim() } : {}),
};
}
/** Apply OS modifiers before matching host modifiers, in list order. */
export function resolveHorstTools(
settings: HorstSettings,
platform: string,
hostname: string,
): string[] | undefined {
const osTools = settings.os[horstOsKey(platform) ?? ""];
const hostTools = settings.hosts[hostname.toLowerCase()];
if (!osTools && !hostTools) return undefined;
return [...(osTools ?? []), ...(hostTools ?? [])];
}