zod-opts
Version:
node.js CLI option parser / validator using Zod
154 lines (153 loc) • 6.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateGlobalUsage = generateGlobalUsage;
exports.generateGlobalCommandUsage = generateGlobalCommandUsage;
exports.generateOptionsText = generateOptionsText;
exports.generatePositionalArgumentsText = generatePositionalArgumentsText;
exports.generateCommandsText = generateCommandsText;
exports.generateGlobalHelp = generateGlobalHelp;
exports.generateCommandHelp = generateCommandHelp;
exports.generateGlobalCommandHelp = generateGlobalCommandHelp;
function getBuiltInOptions(version) {
const helpCommand = {
name: "help",
type: "boolean",
required: false,
alias: "h",
description: "Show help",
isArray: false,
};
const versionCommand = {
name: "version",
type: "boolean",
required: false,
alias: "V",
description: "Show version",
isArray: false,
};
return version === undefined ? [helpCommand] : [helpCommand, versionCommand];
}
function addPaddingToTable(rows) {
if (rows.length === 0) {
return rows;
}
const colLength = rows[0].length;
const colMax = Array.from({ length: colLength }, (_, col) => {
const colCells = rows.map((row) => row[col]);
return Math.max(...colCells.map((cell) => cell.length));
});
const rowsPadded = rows.map((row) => {
return row.map((cell, col) => cell.padEnd(colMax[col]));
});
return rowsPadded;
}
function tableToText(rows) {
return rows.map((cells) => cells.join("")).join("\n");
}
function generateGlobalUsage(scriptName, positionalArgs, commandName) {
const positionalStr = positionalArgs
.map((option) => {
const inner = option.isArray ? `${option.name} ...` : `${option.name}`;
if (option.required) {
return `<${inner}>`;
}
return `[${inner}]`;
})
.join(" ");
const commandStr = commandName !== undefined ? `${commandName} ` : "";
return `Usage: ${scriptName} ${commandStr}[options] ${positionalStr}`;
}
function generateGlobalCommandUsage(scriptName) {
return `Usage: ${scriptName} [options] <command>`;
}
function generateDefaultString(option) {
return option.defaultValue !== undefined
? `(default: ${JSON.stringify(option.defaultValue)})`
: "";
}
function generateNameAndArgString(option) {
var _a, _b;
const arrayStr = option.isArray ? " ..." : "";
switch (option.type) {
case "string":
return `--${option.name} <${(_a = option.argumentName) !== null && _a !== void 0 ? _a : "string"}${arrayStr}>`;
case "number":
return `--${option.name} <${(_b = option.argumentName) !== null && _b !== void 0 ? _b : "number"}${arrayStr}>`;
case "boolean":
return `--${option.name}`;
}
}
function generateChoiceString(option) {
if (option.enumValues === undefined) {
return "";
}
return `(choices: ${option.enumValues.map((s) => `"${s}"`).join(", ")})`;
}
function generateDescriptionString(option) {
var _a;
const descriptionStr = (_a = option.description) !== null && _a !== void 0 ? _a : "";
const defaultStr = generateDefaultString(option);
const choiceStr = generateChoiceString(option);
return `${collapseWhiteSpace([descriptionStr, choiceStr, defaultStr])} `;
}
function collapseWhiteSpace(words, splitter = " ") {
return words.filter((s) => s !== "").join(splitter);
}
function generateOptionsText(options, indent = 2) {
const indentStr = " ".repeat(indent);
const table = options.map((option) => {
const aliasStr = option.alias !== undefined ? `-${option.alias}, ` : "";
const nameAndArgStr = `${generateNameAndArgString(option)} `;
const descriptionStr = generateDescriptionString(option);
const requiredStr = option.required ? "[required]" : "";
return [indentStr, aliasStr, nameAndArgStr, descriptionStr, requiredStr];
});
return `Options:\n${tableToText(addPaddingToTable(table))}`;
}
function generatePositionalArgumentsText(positionalArgs, indent = 2) {
if (positionalArgs.length === 0) {
return "";
}
const indentStr = " ".repeat(indent);
const table = positionalArgs.map((arg) => {
const nameAndArgStr = `${arg.name} `;
const descriptionStr = generateDescriptionString(arg);
const requiredStr = arg.required ? "[required]" : "";
return [indentStr, nameAndArgStr, descriptionStr, requiredStr];
});
return `Arguments:\n${tableToText(addPaddingToTable(table))}`;
}
function generateCommandsText(commands, indent = 2) {
const indentStr = " ".repeat(indent);
const table = commands.map((command) => {
const nameStr = `${command.name} `;
const descriptionStr = command.description !== undefined ? `${command.description}` : "";
return [indentStr, nameStr, descriptionStr];
});
return `Commands:\n${tableToText(addPaddingToTable(table))}`;
}
function generateGlobalHelp({ options, positionalArgs, name, description, version, }) {
const globalUsage = generateGlobalUsage(name !== null && name !== void 0 ? name : "program", positionalArgs);
const descriptionStr = description !== undefined ? `${description}` : "";
const optionsWithBuildIn = getBuiltInOptions(version).concat(options);
const optionsText = generateOptionsText(optionsWithBuildIn);
const positionalArgsText = generatePositionalArgumentsText(positionalArgs);
return `${collapseWhiteSpace([globalUsage, descriptionStr, positionalArgsText, optionsText], "\n\n")}\n`;
}
function generateCommandHelp({ command, name, version, }) {
const positionalArg = command.positionalArgs;
const options = command.options;
const globalUsage = generateGlobalUsage(name !== null && name !== void 0 ? name : "script", positionalArg, command.name);
const optionsWithBuildIn = getBuiltInOptions(version).concat(options);
const descriptionStr = command.description !== undefined ? `${command.description}` : "";
const optionsText = generateOptionsText(optionsWithBuildIn);
const positionalArgsText = generatePositionalArgumentsText(positionalArg);
return `${collapseWhiteSpace([globalUsage, descriptionStr, positionalArgsText, optionsText], "\n\n")}\n`;
}
function generateGlobalCommandHelp({ commands, name, description, version, }) {
const globalUsage = generateGlobalCommandUsage(name !== null && name !== void 0 ? name : "script");
const descriptionStr = description !== undefined ? `${description}` : "";
const commandsText = generateCommandsText(commands);
const optionsText = generateOptionsText(getBuiltInOptions(version));
return `${collapseWhiteSpace([globalUsage, descriptionStr, commandsText, optionsText], "\n\n")}\n`;
}