export interface ArgEvaluatable { enabled(): boolean; envs(): EnvVar[]; binary(): string; prefix(): string; suffix(): string; priority(): number; arguments(): Arguments[]; } export type EnvVar = { var: string; val: string; }; export type Arguments = { arg: string; val: string; prio: number; /** Fixed value set — renders a dropdown in the UI instead of a text input. */ values?: string[]; /** JS regex source the value input must match (HTML pattern attr); empty/cleared always valid. */ pattern?: string; }; function compareArgPrio(a: Arguments, b: Arguments) { return a.prio - b.prio; } export class ArgEval { Components: ArgEvaluatable[]; constructor(components: ArgEvaluatable[]) { this.Components = components; } public eval(): string { const active = this.Components.filter((c) => c.enabled()); const env = active.flatMap((c) => c.envs().map((e) => e.var + '=' + e.val)).join(' '); const progs = [...active] .sort((a, b) => a.priority() - b.priority()) .map((c) => [ c.prefix(), c.binary(), ...c .arguments() .sort(compareArgPrio) .flatMap((a) => (a.val ? `${a.arg} ${a.val}` : a.arg)), c.suffix() ] .filter((s) => s !== '') .join(' ') ) .filter((s) => s !== '') .join(' '); return [env, progs, '%command%'].filter((s) => s !== '').join(' '); } }