@immich/cli
Version:
Command Line Interface (CLI) for Immich
1,508 lines • 685 kB
JavaScript
#! /usr/bin/env node
import require$$0 from "node:events";
import require$$1 from "node:child_process";
import path$1, { resolve, join, relative, sep, basename } from "node:path";
import require$$3, { createReadStream, existsSync } from "node:fs";
import require$$4 from "node:process";
import os, { platform } from "node:os";
import require$$0$5, { unwatchFile, watchFile, watch as watch$1, stat as stat$2 } from "fs";
import { realpath as realpath$1, stat as stat$1, lstat as lstat$1, open, readdir as readdir$1 } from "fs/promises";
import require$$4$1, { EventEmitter } from "events";
import * as sysPath from "path";
import sysPath__default from "path";
import { lstat, stat, readdir, realpath, writeFile, readFile, unlink, mkdir } from "node:fs/promises";
import { Readable } from "node:stream";
import require$$0$3, { type } from "os";
import require$$0$1 from "readline";
import require$$0$2 from "util";
import require$$0$4 from "stream";
import { createHash } from "node:crypto";
import require$$0$6 from "process";
import require$$0$7 from "buffer";
var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
function getDefaultExportFromCjs(x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
}
var commander$1 = {};
var argument = {};
var error$1 = {};
var hasRequiredError$1;
function requireError$1() {
if (hasRequiredError$1) return error$1;
hasRequiredError$1 = 1;
class CommanderError2 extends Error {
/**
* Constructs the CommanderError class
* @param {number} exitCode suggested exit code which could be used with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
*/
constructor(exitCode, code, message) {
super(message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
this.code = code;
this.exitCode = exitCode;
this.nestedError = void 0;
}
}
class InvalidArgumentError2 extends CommanderError2 {
/**
* Constructs the InvalidArgumentError class
* @param {string} [message] explanation of why argument is invalid
*/
constructor(message) {
super(1, "commander.invalidArgument", message);
Error.captureStackTrace(this, this.constructor);
this.name = this.constructor.name;
}
}
error$1.CommanderError = CommanderError2;
error$1.InvalidArgumentError = InvalidArgumentError2;
return error$1;
}
var hasRequiredArgument;
function requireArgument() {
if (hasRequiredArgument) return argument;
hasRequiredArgument = 1;
const { InvalidArgumentError: InvalidArgumentError2 } = requireError$1();
class Argument2 {
/**
* Initialize a new command argument with the given name and description.
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @param {string} name
* @param {string} [description]
*/
constructor(name, description) {
this.description = description || "";
this.variadic = false;
this.parseArg = void 0;
this.defaultValue = void 0;
this.defaultValueDescription = void 0;
this.argChoices = void 0;
switch (name[0]) {
case "<":
this.required = true;
this._name = name.slice(1, -1);
break;
case "[":
this.required = false;
this._name = name.slice(1, -1);
break;
default:
this.required = true;
this._name = name;
break;
}
if (this._name.length > 3 && this._name.slice(-3) === "...") {
this.variadic = true;
this._name = this._name.slice(0, -3);
}
}
/**
* Return argument name.
*
* @return {string}
*/
name() {
return this._name;
}
/**
* @package
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Argument}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Set the custom handler for processing CLI command arguments into argument values.
*
* @param {Function} [fn]
* @return {Argument}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Only allow argument value to be one of choices.
*
* @param {string[]} values
* @return {Argument}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError2(
`Allowed choices are ${this.argChoices.join(", ")}.`
);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Make argument required.
*
* @returns {Argument}
*/
argRequired() {
this.required = true;
return this;
}
/**
* Make argument optional.
*
* @returns {Argument}
*/
argOptional() {
this.required = false;
return this;
}
}
function humanReadableArgName(arg) {
const nameOutput = arg.name() + (arg.variadic === true ? "..." : "");
return arg.required ? "<" + nameOutput + ">" : "[" + nameOutput + "]";
}
argument.Argument = Argument2;
argument.humanReadableArgName = humanReadableArgName;
return argument;
}
var command = {};
var help = {};
var hasRequiredHelp;
function requireHelp() {
if (hasRequiredHelp) return help;
hasRequiredHelp = 1;
const { humanReadableArgName } = requireArgument();
class Help2 {
constructor() {
this.helpWidth = void 0;
this.sortSubcommands = false;
this.sortOptions = false;
this.showGlobalOptions = false;
}
/**
* Get an array of the visible subcommands. Includes a placeholder for the implicit help command, if there is one.
*
* @param {Command} cmd
* @returns {Command[]}
*/
visibleCommands(cmd) {
const visibleCommands = cmd.commands.filter((cmd2) => !cmd2._hidden);
const helpCommand = cmd._getHelpCommand();
if (helpCommand && !helpCommand._hidden) {
visibleCommands.push(helpCommand);
}
if (this.sortSubcommands) {
visibleCommands.sort((a2, b) => {
return a2.name().localeCompare(b.name());
});
}
return visibleCommands;
}
/**
* Compare options for sort.
*
* @param {Option} a
* @param {Option} b
* @returns {number}
*/
compareOptions(a2, b) {
const getSortKey = (option2) => {
return option2.short ? option2.short.replace(/^-/, "") : option2.long.replace(/^--/, "");
};
return getSortKey(a2).localeCompare(getSortKey(b));
}
/**
* Get an array of the visible options. Includes a placeholder for the implicit help option, if there is one.
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleOptions(cmd) {
const visibleOptions = cmd.options.filter((option2) => !option2.hidden);
const helpOption = cmd._getHelpOption();
if (helpOption && !helpOption.hidden) {
const removeShort = helpOption.short && cmd._findOption(helpOption.short);
const removeLong = helpOption.long && cmd._findOption(helpOption.long);
if (!removeShort && !removeLong) {
visibleOptions.push(helpOption);
} else if (helpOption.long && !removeLong) {
visibleOptions.push(
cmd.createOption(helpOption.long, helpOption.description)
);
} else if (helpOption.short && !removeShort) {
visibleOptions.push(
cmd.createOption(helpOption.short, helpOption.description)
);
}
}
if (this.sortOptions) {
visibleOptions.sort(this.compareOptions);
}
return visibleOptions;
}
/**
* Get an array of the visible global options. (Not including help.)
*
* @param {Command} cmd
* @returns {Option[]}
*/
visibleGlobalOptions(cmd) {
if (!this.showGlobalOptions) return [];
const globalOptions = [];
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
const visibleOptions = ancestorCmd.options.filter(
(option2) => !option2.hidden
);
globalOptions.push(...visibleOptions);
}
if (this.sortOptions) {
globalOptions.sort(this.compareOptions);
}
return globalOptions;
}
/**
* Get an array of the arguments if any have a description.
*
* @param {Command} cmd
* @returns {Argument[]}
*/
visibleArguments(cmd) {
if (cmd._argsDescription) {
cmd.registeredArguments.forEach((argument2) => {
argument2.description = argument2.description || cmd._argsDescription[argument2.name()] || "";
});
}
if (cmd.registeredArguments.find((argument2) => argument2.description)) {
return cmd.registeredArguments;
}
return [];
}
/**
* Get the command term to show in the list of subcommands.
*
* @param {Command} cmd
* @returns {string}
*/
subcommandTerm(cmd) {
const args = cmd.registeredArguments.map((arg) => humanReadableArgName(arg)).join(" ");
return cmd._name + (cmd._aliases[0] ? "|" + cmd._aliases[0] : "") + (cmd.options.length ? " [options]" : "") + // simplistic check for non-help option
(args ? " " + args : "");
}
/**
* Get the option term to show in the list of options.
*
* @param {Option} option
* @returns {string}
*/
optionTerm(option2) {
return option2.flags;
}
/**
* Get the argument term to show in the list of arguments.
*
* @param {Argument} argument
* @returns {string}
*/
argumentTerm(argument2) {
return argument2.name();
}
/**
* Get the longest command term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestSubcommandTermLength(cmd, helper) {
return helper.visibleCommands(cmd).reduce((max, command2) => {
return Math.max(max, helper.subcommandTerm(command2).length);
}, 0);
}
/**
* Get the longest option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestOptionTermLength(cmd, helper) {
return helper.visibleOptions(cmd).reduce((max, option2) => {
return Math.max(max, helper.optionTerm(option2).length);
}, 0);
}
/**
* Get the longest global option term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestGlobalOptionTermLength(cmd, helper) {
return helper.visibleGlobalOptions(cmd).reduce((max, option2) => {
return Math.max(max, helper.optionTerm(option2).length);
}, 0);
}
/**
* Get the longest argument term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
longestArgumentTermLength(cmd, helper) {
return helper.visibleArguments(cmd).reduce((max, argument2) => {
return Math.max(max, helper.argumentTerm(argument2).length);
}, 0);
}
/**
* Get the command usage to be displayed at the top of the built-in help.
*
* @param {Command} cmd
* @returns {string}
*/
commandUsage(cmd) {
let cmdName = cmd._name;
if (cmd._aliases[0]) {
cmdName = cmdName + "|" + cmd._aliases[0];
}
let ancestorCmdNames = "";
for (let ancestorCmd = cmd.parent; ancestorCmd; ancestorCmd = ancestorCmd.parent) {
ancestorCmdNames = ancestorCmd.name() + " " + ancestorCmdNames;
}
return ancestorCmdNames + cmdName + " " + cmd.usage();
}
/**
* Get the description for the command.
*
* @param {Command} cmd
* @returns {string}
*/
commandDescription(cmd) {
return cmd.description();
}
/**
* Get the subcommand summary to show in the list of subcommands.
* (Fallback to description for backwards compatibility.)
*
* @param {Command} cmd
* @returns {string}
*/
subcommandDescription(cmd) {
return cmd.summary() || cmd.description();
}
/**
* Get the option description to show in the list of options.
*
* @param {Option} option
* @return {string}
*/
optionDescription(option2) {
const extraInfo = [];
if (option2.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${option2.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
);
}
if (option2.defaultValue !== void 0) {
const showDefault = option2.required || option2.optional || option2.isBoolean() && typeof option2.defaultValue === "boolean";
if (showDefault) {
extraInfo.push(
`default: ${option2.defaultValueDescription || JSON.stringify(option2.defaultValue)}`
);
}
}
if (option2.presetArg !== void 0 && option2.optional) {
extraInfo.push(`preset: ${JSON.stringify(option2.presetArg)}`);
}
if (option2.envVar !== void 0) {
extraInfo.push(`env: ${option2.envVar}`);
}
if (extraInfo.length > 0) {
return `${option2.description} (${extraInfo.join(", ")})`;
}
return option2.description;
}
/**
* Get the argument description to show in the list of arguments.
*
* @param {Argument} argument
* @return {string}
*/
argumentDescription(argument2) {
const extraInfo = [];
if (argument2.argChoices) {
extraInfo.push(
// use stringify to match the display of the default value
`choices: ${argument2.argChoices.map((choice) => JSON.stringify(choice)).join(", ")}`
);
}
if (argument2.defaultValue !== void 0) {
extraInfo.push(
`default: ${argument2.defaultValueDescription || JSON.stringify(argument2.defaultValue)}`
);
}
if (extraInfo.length > 0) {
const extraDescripton = `(${extraInfo.join(", ")})`;
if (argument2.description) {
return `${argument2.description} ${extraDescripton}`;
}
return extraDescripton;
}
return argument2.description;
}
/**
* Generate the built-in help text.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {string}
*/
formatHelp(cmd, helper) {
const termWidth = helper.padWidth(cmd, helper);
const helpWidth = helper.helpWidth || 80;
const itemIndentWidth = 2;
const itemSeparatorWidth = 2;
function formatItem(term, description) {
if (description) {
const fullText = `${term.padEnd(termWidth + itemSeparatorWidth)}${description}`;
return helper.wrap(
fullText,
helpWidth - itemIndentWidth,
termWidth + itemSeparatorWidth
);
}
return term;
}
function formatList(textArray) {
return textArray.join("\n").replace(/^/gm, " ".repeat(itemIndentWidth));
}
let output = [`Usage: ${helper.commandUsage(cmd)}`, ""];
const commandDescription = helper.commandDescription(cmd);
if (commandDescription.length > 0) {
output = output.concat([
helper.wrap(commandDescription, helpWidth, 0),
""
]);
}
const argumentList = helper.visibleArguments(cmd).map((argument2) => {
return formatItem(
helper.argumentTerm(argument2),
helper.argumentDescription(argument2)
);
});
if (argumentList.length > 0) {
output = output.concat(["Arguments:", formatList(argumentList), ""]);
}
const optionList = helper.visibleOptions(cmd).map((option2) => {
return formatItem(
helper.optionTerm(option2),
helper.optionDescription(option2)
);
});
if (optionList.length > 0) {
output = output.concat(["Options:", formatList(optionList), ""]);
}
if (this.showGlobalOptions) {
const globalOptionList = helper.visibleGlobalOptions(cmd).map((option2) => {
return formatItem(
helper.optionTerm(option2),
helper.optionDescription(option2)
);
});
if (globalOptionList.length > 0) {
output = output.concat([
"Global Options:",
formatList(globalOptionList),
""
]);
}
}
const commandList = helper.visibleCommands(cmd).map((cmd2) => {
return formatItem(
helper.subcommandTerm(cmd2),
helper.subcommandDescription(cmd2)
);
});
if (commandList.length > 0) {
output = output.concat(["Commands:", formatList(commandList), ""]);
}
return output.join("\n");
}
/**
* Calculate the pad width from the maximum term length.
*
* @param {Command} cmd
* @param {Help} helper
* @returns {number}
*/
padWidth(cmd, helper) {
return Math.max(
helper.longestOptionTermLength(cmd, helper),
helper.longestGlobalOptionTermLength(cmd, helper),
helper.longestSubcommandTermLength(cmd, helper),
helper.longestArgumentTermLength(cmd, helper)
);
}
/**
* Wrap the given string to width characters per line, with lines after the first indented.
* Do not wrap if insufficient room for wrapping (minColumnWidth), or string is manually formatted.
*
* @param {string} str
* @param {number} width
* @param {number} indent
* @param {number} [minColumnWidth=40]
* @return {string}
*
*/
wrap(str, width, indent, minColumnWidth = 40) {
const indents = " \\f\\t\\v - \uFEFF";
const manualIndent = new RegExp(`[\\n][${indents}]+`);
if (str.match(manualIndent)) return str;
const columnWidth = width - indent;
if (columnWidth < minColumnWidth) return str;
const leadingStr = str.slice(0, indent);
const columnText = str.slice(indent).replace("\r\n", "\n");
const indentString = " ".repeat(indent);
const zeroWidthSpace = "";
const breaks = `\\s${zeroWidthSpace}`;
const regex = new RegExp(
`
|.{1,${columnWidth - 1}}([${breaks}]|$)|[^${breaks}]+?([${breaks}]|$)`,
"g"
);
const lines = columnText.match(regex) || [];
return leadingStr + lines.map((line, i) => {
if (line === "\n") return "";
return (i > 0 ? indentString : "") + line.trimEnd();
}).join("\n");
}
}
help.Help = Help2;
return help;
}
var option = {};
var hasRequiredOption;
function requireOption() {
if (hasRequiredOption) return option;
hasRequiredOption = 1;
const { InvalidArgumentError: InvalidArgumentError2 } = requireError$1();
class Option2 {
/**
* Initialize a new `Option` with the given `flags` and `description`.
*
* @param {string} flags
* @param {string} [description]
*/
constructor(flags, description) {
this.flags = flags;
this.description = description || "";
this.required = flags.includes("<");
this.optional = flags.includes("[");
this.variadic = /\w\.\.\.[>\]]$/.test(flags);
this.mandatory = false;
const optionFlags = splitOptionFlags(flags);
this.short = optionFlags.shortFlag;
this.long = optionFlags.longFlag;
this.negate = false;
if (this.long) {
this.negate = this.long.startsWith("--no-");
}
this.defaultValue = void 0;
this.defaultValueDescription = void 0;
this.presetArg = void 0;
this.envVar = void 0;
this.parseArg = void 0;
this.hidden = false;
this.argChoices = void 0;
this.conflictsWith = [];
this.implied = void 0;
}
/**
* Set the default value, and optionally supply the description to be displayed in the help.
*
* @param {*} value
* @param {string} [description]
* @return {Option}
*/
default(value, description) {
this.defaultValue = value;
this.defaultValueDescription = description;
return this;
}
/**
* Preset to use when option used without option-argument, especially optional but also boolean and negated.
* The custom processing (parseArg) is called.
*
* @example
* new Option('--color').default('GREYSCALE').preset('RGB');
* new Option('--donate [amount]').preset('20').argParser(parseFloat);
*
* @param {*} arg
* @return {Option}
*/
preset(arg) {
this.presetArg = arg;
return this;
}
/**
* Add option name(s) that conflict with this option.
* An error will be displayed if conflicting options are found during parsing.
*
* @example
* new Option('--rgb').conflicts('cmyk');
* new Option('--js').conflicts(['ts', 'jsx']);
*
* @param {(string | string[])} names
* @return {Option}
*/
conflicts(names) {
this.conflictsWith = this.conflictsWith.concat(names);
return this;
}
/**
* Specify implied option values for when this option is set and the implied options are not.
*
* The custom processing (parseArg) is not called on the implied values.
*
* @example
* program
* .addOption(new Option('--log', 'write logging information to file'))
* .addOption(new Option('--trace', 'log extra details').implies({ log: 'trace.txt' }));
*
* @param {object} impliedOptionValues
* @return {Option}
*/
implies(impliedOptionValues) {
let newImplied = impliedOptionValues;
if (typeof impliedOptionValues === "string") {
newImplied = { [impliedOptionValues]: true };
}
this.implied = Object.assign(this.implied || {}, newImplied);
return this;
}
/**
* Set environment variable to check for option value.
*
* An environment variable is only used if when processed the current option value is
* undefined, or the source of the current value is 'default' or 'config' or 'env'.
*
* @param {string} name
* @return {Option}
*/
env(name) {
this.envVar = name;
return this;
}
/**
* Set the custom handler for processing CLI option arguments into option values.
*
* @param {Function} [fn]
* @return {Option}
*/
argParser(fn) {
this.parseArg = fn;
return this;
}
/**
* Whether the option is mandatory and must have a value after parsing.
*
* @param {boolean} [mandatory=true]
* @return {Option}
*/
makeOptionMandatory(mandatory = true) {
this.mandatory = !!mandatory;
return this;
}
/**
* Hide option in help.
*
* @param {boolean} [hide=true]
* @return {Option}
*/
hideHelp(hide = true) {
this.hidden = !!hide;
return this;
}
/**
* @package
*/
_concatValue(value, previous) {
if (previous === this.defaultValue || !Array.isArray(previous)) {
return [value];
}
return previous.concat(value);
}
/**
* Only allow option value to be one of choices.
*
* @param {string[]} values
* @return {Option}
*/
choices(values) {
this.argChoices = values.slice();
this.parseArg = (arg, previous) => {
if (!this.argChoices.includes(arg)) {
throw new InvalidArgumentError2(
`Allowed choices are ${this.argChoices.join(", ")}.`
);
}
if (this.variadic) {
return this._concatValue(arg, previous);
}
return arg;
};
return this;
}
/**
* Return option name.
*
* @return {string}
*/
name() {
if (this.long) {
return this.long.replace(/^--/, "");
}
return this.short.replace(/^-/, "");
}
/**
* Return option name, in a camelcase format that can be used
* as a object attribute key.
*
* @return {string}
*/
attributeName() {
return camelcase(this.name().replace(/^no-/, ""));
}
/**
* Check if `arg` matches the short or long flag.
*
* @param {string} arg
* @return {boolean}
* @package
*/
is(arg) {
return this.short === arg || this.long === arg;
}
/**
* Return whether a boolean option.
*
* Options are one of boolean, negated, required argument, or optional argument.
*
* @return {boolean}
* @package
*/
isBoolean() {
return !this.required && !this.optional && !this.negate;
}
}
class DualOptions {
/**
* @param {Option[]} options
*/
constructor(options2) {
this.positiveOptions = /* @__PURE__ */ new Map();
this.negativeOptions = /* @__PURE__ */ new Map();
this.dualOptions = /* @__PURE__ */ new Set();
options2.forEach((option2) => {
if (option2.negate) {
this.negativeOptions.set(option2.attributeName(), option2);
} else {
this.positiveOptions.set(option2.attributeName(), option2);
}
});
this.negativeOptions.forEach((value, key) => {
if (this.positiveOptions.has(key)) {
this.dualOptions.add(key);
}
});
}
/**
* Did the value come from the option, and not from possible matching dual option?
*
* @param {*} value
* @param {Option} option
* @returns {boolean}
*/
valueFromOption(value, option2) {
const optionKey = option2.attributeName();
if (!this.dualOptions.has(optionKey)) return true;
const preset = this.negativeOptions.get(optionKey).presetArg;
const negativeValue = preset !== void 0 ? preset : false;
return option2.negate === (negativeValue === value);
}
}
function camelcase(str) {
return str.split("-").reduce((str2, word) => {
return str2 + word[0].toUpperCase() + word.slice(1);
});
}
function splitOptionFlags(flags) {
let shortFlag;
let longFlag;
const flagParts = flags.split(/[ |,]+/);
if (flagParts.length > 1 && !/^[[<]/.test(flagParts[1]))
shortFlag = flagParts.shift();
longFlag = flagParts.shift();
if (!shortFlag && /^-[^-]$/.test(longFlag)) {
shortFlag = longFlag;
longFlag = void 0;
}
return { shortFlag, longFlag };
}
option.Option = Option2;
option.DualOptions = DualOptions;
return option;
}
var suggestSimilar = {};
var hasRequiredSuggestSimilar;
function requireSuggestSimilar() {
if (hasRequiredSuggestSimilar) return suggestSimilar;
hasRequiredSuggestSimilar = 1;
const maxDistance = 3;
function editDistance(a2, b) {
if (Math.abs(a2.length - b.length) > maxDistance)
return Math.max(a2.length, b.length);
const d = [];
for (let i = 0; i <= a2.length; i++) {
d[i] = [i];
}
for (let j2 = 0; j2 <= b.length; j2++) {
d[0][j2] = j2;
}
for (let j2 = 1; j2 <= b.length; j2++) {
for (let i = 1; i <= a2.length; i++) {
let cost = 1;
if (a2[i - 1] === b[j2 - 1]) {
cost = 0;
} else {
cost = 1;
}
d[i][j2] = Math.min(
d[i - 1][j2] + 1,
// deletion
d[i][j2 - 1] + 1,
// insertion
d[i - 1][j2 - 1] + cost
// substitution
);
if (i > 1 && j2 > 1 && a2[i - 1] === b[j2 - 2] && a2[i - 2] === b[j2 - 1]) {
d[i][j2] = Math.min(d[i][j2], d[i - 2][j2 - 2] + 1);
}
}
}
return d[a2.length][b.length];
}
function suggestSimilar$1(word, candidates) {
if (!candidates || candidates.length === 0) return "";
candidates = Array.from(new Set(candidates));
const searchingOptions = word.startsWith("--");
if (searchingOptions) {
word = word.slice(2);
candidates = candidates.map((candidate) => candidate.slice(2));
}
let similar = [];
let bestDistance = maxDistance;
const minSimilarity = 0.4;
candidates.forEach((candidate) => {
if (candidate.length <= 1) return;
const distance = editDistance(word, candidate);
const length = Math.max(word.length, candidate.length);
const similarity = (length - distance) / length;
if (similarity > minSimilarity) {
if (distance < bestDistance) {
bestDistance = distance;
similar = [candidate];
} else if (distance === bestDistance) {
similar.push(candidate);
}
}
});
similar.sort((a2, b) => a2.localeCompare(b));
if (searchingOptions) {
similar = similar.map((candidate) => `--${candidate}`);
}
if (similar.length > 1) {
return `
(Did you mean one of ${similar.join(", ")}?)`;
}
if (similar.length === 1) {
return `
(Did you mean ${similar[0]}?)`;
}
return "";
}
suggestSimilar.suggestSimilar = suggestSimilar$1;
return suggestSimilar;
}
var hasRequiredCommand;
function requireCommand() {
if (hasRequiredCommand) return command;
hasRequiredCommand = 1;
const EventEmitter2 = require$$0.EventEmitter;
const childProcess = require$$1;
const path2 = path$1;
const fs2 = require$$3;
const process2 = require$$4;
const { Argument: Argument2, humanReadableArgName } = requireArgument();
const { CommanderError: CommanderError2 } = requireError$1();
const { Help: Help2 } = requireHelp();
const { Option: Option2, DualOptions } = requireOption();
const { suggestSimilar: suggestSimilar2 } = requireSuggestSimilar();
class Command2 extends EventEmitter2 {
/**
* Initialize a new `Command`.
*
* @param {string} [name]
*/
constructor(name) {
super();
this.commands = [];
this.options = [];
this.parent = null;
this._allowUnknownOption = false;
this._allowExcessArguments = true;
this.registeredArguments = [];
this._args = this.registeredArguments;
this.args = [];
this.rawArgs = [];
this.processedArgs = [];
this._scriptPath = null;
this._name = name || "";
this._optionValues = {};
this._optionValueSources = {};
this._storeOptionsAsProperties = false;
this._actionHandler = null;
this._executableHandler = false;
this._executableFile = null;
this._executableDir = null;
this._defaultCommandName = null;
this._exitCallback = null;
this._aliases = [];
this._combineFlagAndOptionalValue = true;
this._description = "";
this._summary = "";
this._argsDescription = void 0;
this._enablePositionalOptions = false;
this._passThroughOptions = false;
this._lifeCycleHooks = {};
this._showHelpAfterError = false;
this._showSuggestionAfterError = true;
this._outputConfiguration = {
writeOut: (str) => process2.stdout.write(str),
writeErr: (str) => process2.stderr.write(str),
getOutHelpWidth: () => process2.stdout.isTTY ? process2.stdout.columns : void 0,
getErrHelpWidth: () => process2.stderr.isTTY ? process2.stderr.columns : void 0,
outputError: (str, write) => write(str)
};
this._hidden = false;
this._helpOption = void 0;
this._addImplicitHelpCommand = void 0;
this._helpCommand = void 0;
this._helpConfiguration = {};
}
/**
* Copy settings that are useful to have in common across root command and subcommands.
*
* (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)
*
* @param {Command} sourceCommand
* @return {Command} `this` command for chaining
*/
copyInheritedSettings(sourceCommand) {
this._outputConfiguration = sourceCommand._outputConfiguration;
this._helpOption = sourceCommand._helpOption;
this._helpCommand = sourceCommand._helpCommand;
this._helpConfiguration = sourceCommand._helpConfiguration;
this._exitCallback = sourceCommand._exitCallback;
this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;
this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;
this._allowExcessArguments = sourceCommand._allowExcessArguments;
this._enablePositionalOptions = sourceCommand._enablePositionalOptions;
this._showHelpAfterError = sourceCommand._showHelpAfterError;
this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;
return this;
}
/**
* @returns {Command[]}
* @private
*/
_getCommandAndAncestors() {
const result = [];
for (let command2 = this; command2; command2 = command2.parent) {
result.push(command2);
}
return result;
}
/**
* Define a command.
*
* There are two styles of command: pay attention to where to put the description.
*
* @example
* // Command implemented using action handler (description is supplied separately to `.command`)
* program
* .command('clone <source> [destination]')
* .description('clone a repository into a newly created directory')
* .action((source, destination) => {
* console.log('clone command called');
* });
*
* // Command implemented using separate executable file (description is second parameter to `.command`)
* program
* .command('start <service>', 'start named service')
* .command('stop [service]', 'stop named service, or all if no name supplied');
*
* @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`
* @param {(object | string)} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)
* @param {object} [execOpts] - configuration options (for executable)
* @return {Command} returns new command for action handler, or `this` for executable command
*/
command(nameAndArgs, actionOptsOrExecDesc, execOpts) {
let desc = actionOptsOrExecDesc;
let opts = execOpts;
if (typeof desc === "object" && desc !== null) {
opts = desc;
desc = null;
}
opts = opts || {};
const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);
const cmd = this.createCommand(name);
if (desc) {
cmd.description(desc);
cmd._executableHandler = true;
}
if (opts.isDefault) this._defaultCommandName = cmd._name;
cmd._hidden = !!(opts.noHelp || opts.hidden);
cmd._executableFile = opts.executableFile || null;
if (args) cmd.arguments(args);
this._registerCommand(cmd);
cmd.parent = this;
cmd.copyInheritedSettings(this);
if (desc) return this;
return cmd;
}
/**
* Factory routine to create a new unattached command.
*
* See .command() for creating an attached subcommand, which uses this routine to
* create the command. You can override createCommand to customise subcommands.
*
* @param {string} [name]
* @return {Command} new command
*/
createCommand(name) {
return new Command2(name);
}
/**
* You can customise the help with a subclass of Help by overriding createHelp,
* or by overriding Help properties using configureHelp().
*
* @return {Help}
*/
createHelp() {
return Object.assign(new Help2(), this.configureHelp());
}
/**
* You can customise the help by overriding Help properties using configureHelp(),
* or with a subclass of Help by overriding createHelp().
*
* @param {object} [configuration] - configuration options
* @return {(Command | object)} `this` command for chaining, or stored configuration
*/
configureHelp(configuration) {
if (configuration === void 0) return this._helpConfiguration;
this._helpConfiguration = configuration;
return this;
}
/**
* The default output goes to stdout and stderr. You can customise this for special
* applications. You can also customise the display of errors by overriding outputError.
*
* The configuration properties are all functions:
*
* // functions to change where being written, stdout and stderr
* writeOut(str)
* writeErr(str)
* // matching functions to specify width for wrapping help
* getOutHelpWidth()
* getErrHelpWidth()
* // functions based on what is being written out
* outputError(str, write) // used for displaying errors, and not used for displaying help
*
* @param {object} [configuration] - configuration options
* @return {(Command | object)} `this` command for chaining, or stored configuration
*/
configureOutput(configuration) {
if (configuration === void 0) return this._outputConfiguration;
Object.assign(this._outputConfiguration, configuration);
return this;
}
/**
* Display the help or a custom message after an error occurs.
*
* @param {(boolean|string)} [displayHelp]
* @return {Command} `this` command for chaining
*/
showHelpAfterError(displayHelp = true) {
if (typeof displayHelp !== "string") displayHelp = !!displayHelp;
this._showHelpAfterError = displayHelp;
return this;
}
/**
* Display suggestion of similar commands for unknown commands, or options for unknown options.
*
* @param {boolean} [displaySuggestion]
* @return {Command} `this` command for chaining
*/
showSuggestionAfterError(displaySuggestion = true) {
this._showSuggestionAfterError = !!displaySuggestion;
return this;
}
/**
* Add a prepared subcommand.
*
* See .command() for creating an attached subcommand which inherits settings from its parent.
*
* @param {Command} cmd - new subcommand
* @param {object} [opts] - configuration options
* @return {Command} `this` command for chaining
*/
addCommand(cmd, opts) {
if (!cmd._name) {
throw new Error(`Command passed to .addCommand() must have a name
- specify the name in Command constructor or using .name()`);
}
opts = opts || {};
if (opts.isDefault) this._defaultCommandName = cmd._name;
if (opts.noHelp || opts.hidden) cmd._hidden = true;
this._registerCommand(cmd);
cmd.parent = this;
cmd._checkForBrokenPassThrough();
return this;
}
/**
* Factory routine to create a new unattached argument.
*
* See .argument() for creating an attached argument, which uses this routine to
* create the argument. You can override createArgument to return a custom argument.
*
* @param {string} name
* @param {string} [description]
* @return {Argument} new argument
*/
createArgument(name, description) {
return new Argument2(name, description);
}
/**
* Define argument syntax for command.
*
* The default is that the argument is required, and you can explicitly
* indicate this with <> around the name. Put [] around the name for an optional argument.
*
* @example
* program.argument('<input-file>');
* program.argument('[output-file]');
*
* @param {string} name
* @param {string} [description]
* @param {(Function|*)} [fn] - custom argument processing function
* @param {*} [defaultValue]
* @return {Command} `this` command for chaining
*/
argument(name, description, fn, defaultValue) {
const argument2 = this.createArgument(name, description);
if (typeof fn === "function") {
argument2.default(defaultValue).argParser(fn);
} else {
argument2.default(fn);
}
this.addArgument(argument2);
return this;
}
/**
* Define argument syntax for command, adding multiple at once (without descriptions).
*
* See also .argument().
*
* @example
* program.arguments('<cmd> [env]');
*
* @param {string} names
* @return {Command} `this` command for chaining
*/
arguments(names) {
names.trim().split(/ +/).forEach((detail) => {
this.argument(detail);
});
return this;
}
/**
* Define argument syntax for command, adding a prepared argument.
*
* @param {Argument} argument
* @return {Command} `this` command for chaining
*/
addArgument(argument2) {
const previousArgument = this.registeredArguments.slice(-1)[0];
if (previousArgument && previousArgument.variadic) {
throw new Error(
`only the last argument can be variadic '${previousArgument.name()}'`
);
}
if (argument2.required && argument2.defaultValue !== void 0 && argument2.parseArg === void 0) {
throw new Error(
`a default value for a required argument is never used: '${argument2.name()}'`
);
}
this.registeredArguments.push(argument2);
return this;
}
/**
* Customise or override default help command. By default a help command is automatically added if your command has subcommands.
*
* @example
* program.helpCommand('help [cmd]');
* program.helpCommand('help [cmd]', 'show help');
* program.helpCommand(false); // suppress default help command
* program.helpCommand(true); // add help command even if no subcommands
*
* @param {string|boolean} enableOrNameAndArgs - enable with custom name and/or arguments, or boolean to override whether added
* @param {string} [description] - custom description
* @return {Command} `this` command for chaining
*/
helpCommand(enableOrNameAndArgs, description) {
if (typeof enableOrNameAndArgs === "boolean") {
this._addImplicitHelpCommand = enableOrNameAndArgs;
return this;
}
enableOrNameAndArgs = enableOrNameAndArgs ?? "help [command]";
const [, helpName, helpArgs] = enableOrNameAndArgs.match(/([^ ]+) *(.*)/);
const helpDescription = description ?? "display help for command";
const helpCommand = this.createCommand(helpName);
helpCommand.helpOption(false);
if (helpArgs) helpCommand.arguments(helpArgs);
if (helpDescription) helpCommand.description(helpDescription);
this._addImplicitHelpCommand = true;
this._helpCommand = helpCommand;
return this;
}
/**
* Add prepared custom help command.
*
* @param {(Command|string|boolean)} helpCommand - custom help command, or deprecated enableOrNameAndArgs as for `.helpCommand()`
* @param {string} [deprecatedDescription] - deprecated custom description used with custom name only
* @return {Command} `this` command for chaining
*/
addHelpCommand(helpCommand, deprecatedDescription) {
if (typeof helpCommand !== "object") {
this.helpCommand(helpCommand, deprecatedDescription);
return this;
}
this._addImplicitHelpCommand = true;
this._helpCommand = helpCommand;
return this;
}
/**
* Lazy create help command.
*
* @return {(Command|null)}
* @package
*/
_getHelpCommand() {
const hasImplicitHelpCommand = this._addImplicitHelpCommand ?? (this.commands.length && !this._actionHandler && !this._findCommand("help"));
if (hasImplicitHelpCommand) {
if (this._helpCommand === void 0) {
this.helpCommand(void 0, void 0);
}
return this._helpCommand;
}
return null;
}
/**
* Add hook for life cycle event.
*
* @param {string} event
* @param {Function} listener
* @return {Command} `this` command for chaining
*/
hook(event, listener) {
const allowedValues = ["preSubcommand", "preAction", "postAction"];
if (!allowedValues.includes(event)) {
throw new Error(`Unexpected value for event passed to hook : '${event}'.
Expecting one of '${allowedValues.join("', '")}'`);
}
if (this._lifeCycleHooks[event]) {
this._lifeCycleHooks[event].push(listener);
} else {
this._lifeCycleHooks[event] = [listener];
}
return this;
}
/**
* Register callback to use as replacement for calling process.exit.
*
* @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing
* @return {Command} `this` command for chaining
*/
exitOverride(fn) {
if (fn) {
this._exitCallback = fn;
} else {
this._exitCallback = (err) => {
if (err.code !== "commander.executeSubCommandAsync") {
throw err;
}
};
}
return this;
}
/**
* Call process.exit, and _exitCallback if defined.
*
* @param {number} exitCode exit code for using with process.exit
* @param {string} code an id string representing the error
* @param {string} message human-readable description of the error
* @return never
* @private
*/
_exit(exitCode, code, message) {
if (this._exitCallback) {
this._exitCallback(new CommanderError2(exitCode, code, message));
}
process2.exit(exitCode);
}
/**
* Register callback `fn` for the command.
*
* @example
* program
* .command('serve')
* .description('start service')
* .action(function() {
* // do work here
* });
*
* @param {Function} fn
* @return {Command} `this` command for chaining
*/
action(fn) {
const listener = (args) => {
const expectedArgsCount = this.registeredArguments.length;
const actionArgs = args.slice(0, expectedArgsCount);
if (this._storeOptionsAsProperties) {
actionArgs[expectedArgsCount] = this;
} else {
actionArgs[expectedArgsCount] = this.opts();
}
actionArgs.push(this);
return fn.apply(this, actionArgs);
};
this._actionHandler = listener;
return this;
}
/**
* Factory routine to create a new unattached option.
*
* See .option() for creating an attached option, which uses this routine to
* create the option. You can override createOption to return a custom option.
*
* @param {string} flags
* @param {string} [description]
* @return {Option} new option
*/
createOption(flags, description) {
return new Option2(flags, description);
}
/**
* Wrap parseArgs to catch 'commander.invalidArgument'.
*
* @param {(Option | Argument)} target
* @param {string} value
* @param {*} previous
* @param {string} invalidArgumentMessage
* @private
*/
_callParseArg(target, value, previous, invalidArgumentMessage) {
try {
return target.parseArg(value, previous);
} catch (err) {
if (err.code === "commander.invalidArgument") {
const message = `${invalidArgumentMessage} ${err.message}`;
this.error(message, { exitCode: err.exitCode, code: err.code });
}
throw err;
}
}
/**
* Check for option flag conflicts.
* Register option if no conflicts found, or throw on conflict.
*
* @param {Option} option
* @private
*/
_registerOption(option2) {
const matchingOption = option2.short && this._findOption(option2.short) || option2.long && this._findOption(option2.long);
if (matchingOption) {
const matchingFlag = option2.long && this._findOption(option2.long) ? option2.long : option2.short;
throw new Error(`Cannot add option '${option2.flags}'${this._name && ` to command '${this._name}'`} due to conflicting flag '${matchingFlag}'
- already used by option '${matchingOption.flags}'`);
}
this.options.push(option2);
}
/**
* Check for command name and alias conflicts with existing commands.
* Register command if no conflicts found, or throw on conflict.
*
* @param {Command} command
* @private
*/
_registerCommand(command2) {
const knownBy = (cmd) => {
return [cmd.name()].concat(cmd.aliases());
};
const alreadyUsed = knownBy(command2).find(
(name) => this._findCommand(name)
);
if (alreadyUsed) {
const existingCmd = knownBy(this._findCommand(alreadyUsed)).join("|");
const newCmd = knownBy(command2).join("|");
throw new Error(
`cannot add command '${newCmd}' as already have command '${existingCmd}'`
);
}
this.commands.push(command2);
}
/**
* Add an option.
*
* @param {Option} option
* @return {Command} `this` command for chaining
*/
addOption(option2) {
this._registerOption(option2);
const oname = option2.name();
const name = option2.attributeName