Files
Vesktop/src/main/cli.ts

106 lines
3.2 KiB
TypeScript
Raw Normal View History

2025-10-18 17:54:05 +02:00
/*
* Vesktop, a desktop app aiming to give you a snappier Discord Experience
* Copyright (c) 2025 Vendicated and Vesktop contributors
* SPDX-License-Identifier: GPL-3.0-or-later
*/
import { app } from "electron";
import { stripIndent } from "shared/utils/text";
import { parseArgs, ParseArgsOptionDescriptor } from "util";
const options = {
"start-minimized": {
default: false,
type: "boolean",
short: "m",
description: "Start the application minimized to the system tray"
},
version: {
type: "boolean",
short: "v",
description: "Print the application version and exit"
},
help: {
type: "boolean",
short: "h",
description: "Print help information and exit"
},
"user-agent": {
type: "string",
argumentName: "ua",
description: "Set a custom User-Agent. May trigger anti-spam or break voice chat"
},
"user-agent-os": {
type: "string",
description: "Set User-Agent to a specific operating system. May trigger anti-spam or break voice chat",
options: ["windows", "linux", "darwin"]
}
} satisfies Record<
string,
ParseArgsOptionDescriptor & { description: string; options?: string[]; argumentName?: string }
>;
export const CommandLine = parseArgs({
options,
2025-10-18 18:02:50 +02:00
strict: false as true, // we manually check later, so cast to true to get better types
2025-10-18 17:54:05 +02:00
allowPositionals: true
});
export function checkCommandLineForHelpOrVersion() {
const { help, version } = CommandLine.values;
if (version) {
2025-10-18 18:02:50 +02:00
console.log(`Vesktop v${app.getVersion()}`);
2025-10-18 17:54:05 +02:00
app.exit(0);
}
if (help) {
const base = stripIndent`
Vesktop v${app.getVersion()}
Usage: ${process.execPath} [options] [url]
Options:
`;
const optionLines = Object.entries(options)
.sort(([a], [b]) => a.localeCompare(b))
.map(([name, opt]) => {
const flags = [
"short" in opt && `-${opt.short}`,
`--${name}`,
opt.type !== "boolean" &&
("options" in opt ? `<${opt.options.join(" | ")}>` : `<${opt.argumentName ?? opt.type}>`)
]
.filter(Boolean)
.join(" ");
return [flags, opt.description];
});
const padding = optionLines.reduce((max, [flags]) => Math.max(max, flags.length), 0) + 4;
const optionsHelp = optionLines
.map(([flags, description]) => ` ${flags.padEnd(padding, " ")}${description}`)
.join("\n");
2025-10-18 18:02:50 +02:00
console.log(base + "\n" + optionsHelp);
2025-10-18 17:54:05 +02:00
app.exit(0);
}
for (const [name, def] of Object.entries(options)) {
const value = CommandLine.values[name];
2025-10-18 18:02:50 +02:00
if (value == null) continue;
2025-10-18 17:54:05 +02:00
2025-10-18 18:02:50 +02:00
if (typeof value !== def.type) {
console.error(`Invalid options. Expected ${def.type === "boolean" ? "no" : "an"} argument for --${name}`);
app.exit(1);
}
if ("options" in def && !def.options?.includes(value as string)) {
2025-10-18 17:54:05 +02:00
console.error(`Invalid value for --${name}: ${value}\nExpected one of: ${def.options.join(", ")}`);
app.exit(1);
}
}
}