Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1const EventEmitter = require('events').EventEmitter;2const childProcess = require('child_process');3const path = require('path');4const fs = require('fs');5 6const { Argument, humanReadableArgName } = require('./argument.js');7const { CommanderError } = require('./error.js');8const { Help } = require('./help.js');9const { Option, splitOptionFlags } = require('./option.js');10const { suggestSimilar } = require('./suggestSimilar');11 12// @ts-check13 14class Command extends EventEmitter {15 /**16 * Initialize a new `Command`.17 *18 * @param {string} [name]19 */20 21 constructor(name) {22 super();23 /** @type {Command[]} */24 this.commands = [];25 /** @type {Option[]} */26 this.options = [];27 this.parent = null;28 this._allowUnknownOption = false;29 this._allowExcessArguments = true;30 /** @type {Argument[]} */31 this._args = [];32 /** @type {string[]} */33 this.args = []; // cli args with options removed34 this.rawArgs = [];35 this.processedArgs = []; // like .args but after custom processing and collecting variadic36 this._scriptPath = null;37 this._name = name || '';38 this._optionValues = {};39 this._optionValueSources = {}; // default < config < env < cli40 this._storeOptionsAsProperties = false;41 this._actionHandler = null;42 this._executableHandler = false;43 this._executableFile = null; // custom name for executable44 this._defaultCommandName = null;45 this._exitCallback = null;46 this._aliases = [];47 this._combineFlagAndOptionalValue = true;48 this._description = '';49 this._argsDescription = undefined; // legacy50 this._enablePositionalOptions = false;51 this._passThroughOptions = false;52 this._lifeCycleHooks = {}; // a hash of arrays53 /** @type {boolean | string} */54 this._showHelpAfterError = false;55 this._showSuggestionAfterError = false;56 57 // see .configureOutput() for docs58 this._outputConfiguration = {59 writeOut: (str) => process.stdout.write(str),60 writeErr: (str) => process.stderr.write(str),61 getOutHelpWidth: () => process.stdout.isTTY ? process.stdout.columns : undefined,62 getErrHelpWidth: () => process.stderr.isTTY ? process.stderr.columns : undefined,63 outputError: (str, write) => write(str)64 };65 66 this._hidden = false;67 this._hasHelpOption = true;68 this._helpFlags = '-h, --help';69 this._helpDescription = 'display help for command';70 this._helpShortFlag = '-h';71 this._helpLongFlag = '--help';72 this._addImplicitHelpCommand = undefined; // Deliberately undefined, not decided whether true or false73 this._helpCommandName = 'help';74 this._helpCommandnameAndArgs = 'help [command]';75 this._helpCommandDescription = 'display help for command';76 this._helpConfiguration = {};77 }78 79 /**80 * Copy settings that are useful to have in common across root command and subcommands.81 *82 * (Used internally when adding a command using `.command()` so subcommands inherit parent settings.)83 *84 * @param {Command} sourceCommand85 * @return {Command} returns `this` for executable command86 */87 copyInheritedSettings(sourceCommand) {88 this._outputConfiguration = sourceCommand._outputConfiguration;89 this._hasHelpOption = sourceCommand._hasHelpOption;90 this._helpFlags = sourceCommand._helpFlags;91 this._helpDescription = sourceCommand._helpDescription;92 this._helpShortFlag = sourceCommand._helpShortFlag;93 this._helpLongFlag = sourceCommand._helpLongFlag;94 this._helpCommandName = sourceCommand._helpCommandName;95 this._helpCommandnameAndArgs = sourceCommand._helpCommandnameAndArgs;96 this._helpCommandDescription = sourceCommand._helpCommandDescription;97 this._helpConfiguration = sourceCommand._helpConfiguration;98 this._exitCallback = sourceCommand._exitCallback;99 this._storeOptionsAsProperties = sourceCommand._storeOptionsAsProperties;100 this._combineFlagAndOptionalValue = sourceCommand._combineFlagAndOptionalValue;101 this._allowExcessArguments = sourceCommand._allowExcessArguments;102 this._enablePositionalOptions = sourceCommand._enablePositionalOptions;103 this._showHelpAfterError = sourceCommand._showHelpAfterError;104 this._showSuggestionAfterError = sourceCommand._showSuggestionAfterError;105 106 return this;107 }108 109 /**110 * Define a command.111 *112 * There are two styles of command: pay attention to where to put the description.113 *114 * @example115 * // Command implemented using action handler (description is supplied separately to `.command`)116 * program117 * .command('clone <source> [destination]')118 * .description('clone a repository into a newly created directory')119 * .action((source, destination) => {120 * console.log('clone command called');121 * });122 *123 * // Command implemented using separate executable file (description is second parameter to `.command`)124 * program125 * .command('start <service>', 'start named service')126 * .command('stop [service]', 'stop named service, or all if no name supplied');127 *128 * @param {string} nameAndArgs - command name and arguments, args are `<required>` or `[optional]` and last may also be `variadic...`129 * @param {Object|string} [actionOptsOrExecDesc] - configuration options (for action), or description (for executable)130 * @param {Object} [execOpts] - configuration options (for executable)131 * @return {Command} returns new command for action handler, or `this` for executable command132 */133 134 command(nameAndArgs, actionOptsOrExecDesc, execOpts) {135 let desc = actionOptsOrExecDesc;136 let opts = execOpts;137 if (typeof desc === 'object' && desc !== null) {138 opts = desc;139 desc = null;140 }141 opts = opts || {};142 const [, name, args] = nameAndArgs.match(/([^ ]+) *(.*)/);143 144 const cmd = this.createCommand(name);145 if (desc) {146 cmd.description(desc);147 cmd._executableHandler = true;148 }149 if (opts.isDefault) this._defaultCommandName = cmd._name;150 cmd._hidden = !!(opts.noHelp || opts.hidden); // noHelp is deprecated old name for hidden151 cmd._executableFile = opts.executableFile || null; // Custom name for executable file, set missing to null to match constructor152 if (args) cmd.arguments(args);153 this.commands.push(cmd);154 cmd.parent = this;155 cmd.copyInheritedSettings(this);156 157 if (desc) return this;158 return cmd;159 };160 161 /**162 * Factory routine to create a new unattached command.163 *164 * See .command() for creating an attached subcommand, which uses this routine to165 * create the command. You can override createCommand to customise subcommands.166 *167 * @param {string} [name]168 * @return {Command} new command169 */170 171 createCommand(name) {172 return new Command(name);173 };174 175 /**176 * You can customise the help with a subclass of Help by overriding createHelp,177 * or by overriding Help properties using configureHelp().178 *179 * @return {Help}180 */181 182 createHelp() {183 return Object.assign(new Help(), this.configureHelp());184 };185 186 /**187 * You can customise the help by overriding Help properties using configureHelp(),188 * or with a subclass of Help by overriding createHelp().189 *190 * @param {Object} [configuration] - configuration options191 * @return {Command|Object} `this` command for chaining, or stored configuration192 */193 194 configureHelp(configuration) {195 if (configuration === undefined) return this._helpConfiguration;196 197 this._helpConfiguration = configuration;198 return this;199 }200 201 /**202 * The default output goes to stdout and stderr. You can customise this for special203 * applications. You can also customise the display of errors by overriding outputError.204 *205 * The configuration properties are all functions:206 *207 * // functions to change where being written, stdout and stderr208 * writeOut(str)209 * writeErr(str)210 * // matching functions to specify width for wrapping help211 * getOutHelpWidth()212 * getErrHelpWidth()213 * // functions based on what is being written out214 * outputError(str, write) // used for displaying errors, and not used for displaying help215 *216 * @param {Object} [configuration] - configuration options217 * @return {Command|Object} `this` command for chaining, or stored configuration218 */219 220 configureOutput(configuration) {221 if (configuration === undefined) return this._outputConfiguration;222 223 Object.assign(this._outputConfiguration, configuration);224 return this;225 }226 227 /**228 * Display the help or a custom message after an error occurs.229 *230 * @param {boolean|string} [displayHelp]231 * @return {Command} `this` command for chaining232 */233 showHelpAfterError(displayHelp = true) {234 if (typeof displayHelp !== 'string') displayHelp = !!displayHelp;235 this._showHelpAfterError = displayHelp;236 return this;237 }238 239 /**240 * Display suggestion of similar commands for unknown commands, or options for unknown options.241 *242 * @param {boolean} [displaySuggestion]243 * @return {Command} `this` command for chaining244 */245 showSuggestionAfterError(displaySuggestion = true) {246 this._showSuggestionAfterError = !!displaySuggestion;247 return this;248 }249 250 /**251 * Add a prepared subcommand.252 *253 * See .command() for creating an attached subcommand which inherits settings from its parent.254 *255 * @param {Command} cmd - new subcommand256 * @param {Object} [opts] - configuration options257 * @return {Command} `this` command for chaining258 */259 260 addCommand(cmd, opts) {261 if (!cmd._name) throw new Error('Command passed to .addCommand() must have a name');262 263 // To keep things simple, block automatic name generation for deeply nested executables.264 // Fail fast and detect when adding rather than later when parsing.265 function checkExplicitNames(commandArray) {266 commandArray.forEach((cmd) => {267 if (cmd._executableHandler && !cmd._executableFile) {268 throw new Error(`Must specify executableFile for deeply nested executable: ${cmd.name()}`);269 }270 checkExplicitNames(cmd.commands);271 });272 }273 checkExplicitNames(cmd.commands);274 275 opts = opts || {};276 if (opts.isDefault) this._defaultCommandName = cmd._name;277 if (opts.noHelp || opts.hidden) cmd._hidden = true; // modifying passed command due to existing implementation278 279 this.commands.push(cmd);280 cmd.parent = this;281 return this;282 };283 284 /**285 * Factory routine to create a new unattached argument.286 *287 * See .argument() for creating an attached argument, which uses this routine to288 * create the argument. You can override createArgument to return a custom argument.289 *290 * @param {string} name291 * @param {string} [description]292 * @return {Argument} new argument293 */294 295 createArgument(name, description) {296 return new Argument(name, description);297 };298 299 /**300 * Define argument syntax for command.301 *302 * The default is that the argument is required, and you can explicitly303 * indicate this with <> around the name. Put [] around the name for an optional argument.304 *305 * @example306 * program.argument('<input-file>');307 * program.argument('[output-file]');308 *309 * @param {string} name310 * @param {string} [description]311 * @param {Function|*} [fn] - custom argument processing function312 * @param {*} [defaultValue]313 * @return {Command} `this` command for chaining314 */315 argument(name, description, fn, defaultValue) {316 const argument = this.createArgument(name, description);317 if (typeof fn === 'function') {318 argument.default(defaultValue).argParser(fn);319 } else {320 argument.default(fn);321 }322 this.addArgument(argument);323 return this;324 }325 326 /**327 * Define argument syntax for command, adding multiple at once (without descriptions).328 *329 * See also .argument().330 *331 * @example332 * program.arguments('<cmd> [env]');333 *334 * @param {string} names335 * @return {Command} `this` command for chaining336 */337 338 arguments(names) {339 names.split(/ +/).forEach((detail) => {340 this.argument(detail);341 });342 return this;343 };344 345 /**346 * Define argument syntax for command, adding a prepared argument.347 *348 * @param {Argument} argument349 * @return {Command} `this` command for chaining350 */351 addArgument(argument) {352 const previousArgument = this._args.slice(-1)[0];353 if (previousArgument && previousArgument.variadic) {354 throw new Error(`only the last argument can be variadic '${previousArgument.name()}'`);355 }356 if (argument.required && argument.defaultValue !== undefined && argument.parseArg === undefined) {357 throw new Error(`a default value for a required argument is never used: '${argument.name()}'`);358 }359 this._args.push(argument);360 return this;361 }362 363 /**364 * Override default decision whether to add implicit help command.365 *366 * addHelpCommand() // force on367 * addHelpCommand(false); // force off368 * addHelpCommand('help [cmd]', 'display help for [cmd]'); // force on with custom details369 *370 * @return {Command} `this` command for chaining371 */372 373 addHelpCommand(enableOrNameAndArgs, description) {374 if (enableOrNameAndArgs === false) {375 this._addImplicitHelpCommand = false;376 } else {377 this._addImplicitHelpCommand = true;378 if (typeof enableOrNameAndArgs === 'string') {379 this._helpCommandName = enableOrNameAndArgs.split(' ')[0];380 this._helpCommandnameAndArgs = enableOrNameAndArgs;381 }382 this._helpCommandDescription = description || this._helpCommandDescription;383 }384 return this;385 };386 387 /**388 * @return {boolean}389 * @api private390 */391 392 _hasImplicitHelpCommand() {393 if (this._addImplicitHelpCommand === undefined) {394 return this.commands.length && !this._actionHandler && !this._findCommand('help');395 }396 return this._addImplicitHelpCommand;397 };398 399 /**400 * Add hook for life cycle event.401 *402 * @param {string} event403 * @param {Function} listener404 * @return {Command} `this` command for chaining405 */406 407 hook(event, listener) {408 const allowedValues = ['preAction', 'postAction'];409 if (!allowedValues.includes(event)) {410 throw new Error(`Unexpected value for event passed to hook : '${event}'.411Expecting one of '${allowedValues.join("', '")}'`);412 }413 if (this._lifeCycleHooks[event]) {414 this._lifeCycleHooks[event].push(listener);415 } else {416 this._lifeCycleHooks[event] = [listener];417 }418 return this;419 }420 421 /**422 * Register callback to use as replacement for calling process.exit.423 *424 * @param {Function} [fn] optional callback which will be passed a CommanderError, defaults to throwing425 * @return {Command} `this` command for chaining426 */427 428 exitOverride(fn) {429 if (fn) {430 this._exitCallback = fn;431 } else {432 this._exitCallback = (err) => {433 if (err.code !== 'commander.executeSubCommandAsync') {434 throw err;435 } else {436 // Async callback from spawn events, not useful to throw.437 }438 };439 }440 return this;441 };442 443 /**444 * Call process.exit, and _exitCallback if defined.445 *446 * @param {number} exitCode exit code for using with process.exit447 * @param {string} code an id string representing the error448 * @param {string} message human-readable description of the error449 * @return never450 * @api private451 */452 453 _exit(exitCode, code, message) {454 if (this._exitCallback) {455 this._exitCallback(new CommanderError(exitCode, code, message));456 // Expecting this line is not reached.457 }458 process.exit(exitCode);459 };460 461 /**462 * Register callback `fn` for the command.463 *464 * @example465 * program466 * .command('serve')467 * .description('start service')468 * .action(function() {469 * // do work here470 * });471 *472 * @param {Function} fn473 * @return {Command} `this` command for chaining474 */475 476 action(fn) {477 const listener = (args) => {478 // The .action callback takes an extra parameter which is the command or options.479 const expectedArgsCount = this._args.length;480 const actionArgs = args.slice(0, expectedArgsCount);481 if (this._storeOptionsAsProperties) {482 actionArgs[expectedArgsCount] = this; // backwards compatible "options"483 } else {484 actionArgs[expectedArgsCount] = this.opts();485 }486 actionArgs.push(this);487 488 return fn.apply(this, actionArgs);489 };490 this._actionHandler = listener;491 return this;492 };493 494 /**495 * Factory routine to create a new unattached option.496 *497 * See .option() for creating an attached option, which uses this routine to498 * create the option. You can override createOption to return a custom option.499 *500 * @param {string} flags501 * @param {string} [description]502 * @return {Option} new option503 */504 505 createOption(flags, description) {506 return new Option(flags, description);507 };508 509 /**510 * Add an option.511 *512 * @param {Option} option513 * @return {Command} `this` command for chaining514 */515 addOption(option) {516 const oname = option.name();517 const name = option.attributeName();518 519 let defaultValue = option.defaultValue;520 521 // preassign default value for --no-*, [optional], <required>, or plain flag if boolean value522 if (option.negate || option.optional || option.required || typeof defaultValue === 'boolean') {523 // when --no-foo we make sure default is true, unless a --foo option is already defined524 if (option.negate) {525 const positiveLongFlag = option.long.replace(/^--no-/, '--');526 defaultValue = this._findOption(positiveLongFlag) ? this.getOptionValue(name) : true;527 }528 // preassign only if we have a default529 if (defaultValue !== undefined) {530 this.setOptionValueWithSource(name, defaultValue, 'default');531 }532 }533 534 // register the option535 this.options.push(option);536 537 // handler for cli and env supplied values538 const handleOptionValue = (val, invalidValueMessage, valueSource) => {539 // Note: using closure to access lots of lexical scoped variables.540 const oldValue = this.getOptionValue(name);541 542 // custom processing543 if (val !== null && option.parseArg) {544 try {545 val = option.parseArg(val, oldValue === undefined ? defaultValue : oldValue);546 } catch (err) {547 if (err.code === 'commander.invalidArgument') {548 const message = `${invalidValueMessage} ${err.message}`;549 this._displayError(err.exitCode, err.code, message);550 }551 throw err;552 }553 } else if (val !== null && option.variadic) {554 val = option._concatValue(val, oldValue);555 }556 557 // unassigned or boolean value558 if (typeof oldValue === 'boolean' || typeof oldValue === 'undefined') {559 // if no value, negate false, and we have a default, then use it!560 if (val == null) {561 this.setOptionValueWithSource(name, option.negate ? false : defaultValue || true, valueSource);562 } else {563 this.setOptionValueWithSource(name, val, valueSource);564 }565 } else if (val !== null) {566 // reassign567 this.setOptionValueWithSource(name, option.negate ? false : val, valueSource);568 }569 };570 571 this.on('option:' + oname, (val) => {572 const invalidValueMessage = `error: option '${option.flags}' argument '${val}' is invalid.`;573 handleOptionValue(val, invalidValueMessage, 'cli');574 });575 576 if (option.envVar) {577 this.on('optionEnv:' + oname, (val) => {578 const invalidValueMessage = `error: option '${option.flags}' value '${val}' from env '${option.envVar}' is invalid.`;579 handleOptionValue(val, invalidValueMessage, 'env');580 });581 }582 583 return this;584 }585 586 /**587 * Internal implementation shared by .option() and .requiredOption()588 *589 * @api private590 */591 _optionEx(config, flags, description, fn, defaultValue) {592 const option = this.createOption(flags, description);593 option.makeOptionMandatory(!!config.mandatory);594 if (typeof fn === 'function') {595 option.default(defaultValue).argParser(fn);596 } else if (fn instanceof RegExp) {597 // deprecated598 const regex = fn;599 fn = (val, def) => {600 const m = regex.exec(val);601 return m ? m[0] : def;602 };603 option.default(defaultValue).argParser(fn);604 } else {605 option.default(fn);606 }607 608 return this.addOption(option);609 }610 611 /**612 * Define option with `flags`, `description` and optional613 * coercion `fn`.614 *615 * The `flags` string contains the short and/or long flags,616 * separated by comma, a pipe or space. The following are all valid617 * all will output this way when `--help` is used.618 *619 * "-p, --pepper"620 * "-p|--pepper"621 * "-p --pepper"622 *623 * @example624 * // simple boolean defaulting to undefined625 * program.option('-p, --pepper', 'add pepper');626 *627 * program.pepper628 * // => undefined629 *630 * --pepper631 * program.pepper632 * // => true633 *634 * // simple boolean defaulting to true (unless non-negated option is also defined)635 * program.option('-C, --no-cheese', 'remove cheese');636 *637 * program.cheese638 * // => true639 *640 * --no-cheese641 * program.cheese642 * // => false643 *644 * // required argument645 * program.option('-C, --chdir <path>', 'change the working directory');646 *647 * --chdir /tmp648 * program.chdir649 * // => "/tmp"650 *651 * // optional argument652 * program.option('-c, --cheese [type]', 'add cheese [marble]');653 *654 * @param {string} flags655 * @param {string} [description]656 * @param {Function|*} [fn] - custom option processing function or default value657 * @param {*} [defaultValue]658 * @return {Command} `this` command for chaining659 */660 661 option(flags, description, fn, defaultValue) {662 return this._optionEx({}, flags, description, fn, defaultValue);663 };664 665 /**666 * Add a required option which must have a value after parsing. This usually means667 * the option must be specified on the command line. (Otherwise the same as .option().)668 *669 * The `flags` string contains the short and/or long flags, separated by comma, a pipe or space.670 *671 * @param {string} flags672 * @param {string} [description]673 * @param {Function|*} [fn] - custom option processing function or default value674 * @param {*} [defaultValue]675 * @return {Command} `this` command for chaining676 */677 678 requiredOption(flags, description, fn, defaultValue) {679 return this._optionEx({ mandatory: true }, flags, description, fn, defaultValue);680 };681 682 /**683 * Alter parsing of short flags with optional values.684 *685 * @example686 * // for `.option('-f,--flag [value]'):687 * program.combineFlagAndOptionalValue(true); // `-f80` is treated like `--flag=80`, this is the default behaviour688 * program.combineFlagAndOptionalValue(false) // `-fb` is treated like `-f -b`689 *690 * @param {Boolean} [combine=true] - if `true` or omitted, an optional value can be specified directly after the flag.691 */692 combineFlagAndOptionalValue(combine = true) {693 this._combineFlagAndOptionalValue = !!combine;694 return this;695 };696 697 /**698 * Allow unknown options on the command line.699 *700 * @param {Boolean} [allowUnknown=true] - if `true` or omitted, no error will be thrown701 * for unknown options.702 */703 allowUnknownOption(allowUnknown = true) {704 this._allowUnknownOption = !!allowUnknown;705 return this;706 };707 708 /**709 * Allow excess command-arguments on the command line. Pass false to make excess arguments an error.710 *711 * @param {Boolean} [allowExcess=true] - if `true` or omitted, no error will be thrown712 * for excess arguments.713 */714 allowExcessArguments(allowExcess = true) {715 this._allowExcessArguments = !!allowExcess;716 return this;717 };718 719 /**720 * Enable positional options. Positional means global options are specified before subcommands which lets721 * subcommands reuse the same option names, and also enables subcommands to turn on passThroughOptions.722 * The default behaviour is non-positional and global options may appear anywhere on the command line.723 *724 * @param {Boolean} [positional=true]725 */726 enablePositionalOptions(positional = true) {727 this._enablePositionalOptions = !!positional;728 return this;729 };730 731 /**732 * Pass through options that come after command-arguments rather than treat them as command-options,733 * so actual command-options come before command-arguments. Turning this on for a subcommand requires734 * positional options to have been enabled on the program (parent commands).735 * The default behaviour is non-positional and options may appear before or after command-arguments.736 *737 * @param {Boolean} [passThrough=true]738 * for unknown options.739 */740 passThroughOptions(passThrough = true) {741 this._passThroughOptions = !!passThrough;742 if (!!this.parent && passThrough && !this.parent._enablePositionalOptions) {743 throw new Error('passThroughOptions can not be used without turning on enablePositionalOptions for parent command(s)');744 }745 return this;746 };747 748 /**749 * Whether to store option values as properties on command object,750 * or store separately (specify false). In both cases the option values can be accessed using .opts().751 *752 * @param {boolean} [storeAsProperties=true]753 * @return {Command} `this` command for chaining754 */755 756 storeOptionsAsProperties(storeAsProperties = true) {757 this._storeOptionsAsProperties = !!storeAsProperties;758 if (this.options.length) {759 throw new Error('call .storeOptionsAsProperties() before adding options');760 }761 return this;762 };763 764 /**765 * Retrieve option value.766 *767 * @param {string} key768 * @return {Object} value769 */770 771 getOptionValue(key) {772 if (this._storeOptionsAsProperties) {773 return this[key];774 }775 return this._optionValues[key];776 };777 778 /**779 * Store option value.780 *781 * @param {string} key782 * @param {Object} value783 * @return {Command} `this` command for chaining784 */785 786 setOptionValue(key, value) {787 if (this._storeOptionsAsProperties) {788 this[key] = value;789 } else {790 this._optionValues[key] = value;791 }792 return this;793 };794 795 /**796 * Store option value and where the value came from.797 *798 * @param {string} key799 * @param {Object} value800 * @param {string} source - expected values are default/config/env/cli801 * @return {Command} `this` command for chaining802 */803 804 setOptionValueWithSource(key, value, source) {805 this.setOptionValue(key, value);806 this._optionValueSources[key] = source;807 return this;808 }809 810 /**811 * Get source of option value.812 * Expected values are default | config | env | cli813 *814 * @param {string} key815 * @return {string}816 */817 818 getOptionValueSource(key) {819 return this._optionValueSources[key];820 };821 822 /**823 * Get user arguments implied or explicit arguments.824 * Side-effects: set _scriptPath if args included application, and use that to set implicit command name.825 *826 * @api private827 */828 829 _prepareUserArgs(argv, parseOptions) {830 if (argv !== undefined && !Array.isArray(argv)) {831 throw new Error('first parameter to parse must be array or undefined');832 }833 parseOptions = parseOptions || {};834 835 // Default to using process.argv836 if (argv === undefined) {837 argv = process.argv;838 // @ts-ignore: unknown property839 if (process.versions && process.versions.electron) {840 parseOptions.from = 'electron';841 }842 }843 this.rawArgs = argv.slice();844 845 // make it a little easier for callers by supporting various argv conventions846 let userArgs;847 switch (parseOptions.from) {848 case undefined:849 case 'node':850 this._scriptPath = argv[1];851 userArgs = argv.slice(2);852 break;853 case 'electron':854 // @ts-ignore: unknown property855 if (process.defaultApp) {856 this._scriptPath = argv[1];857 userArgs = argv.slice(2);858 } else {859 userArgs = argv.slice(1);860 }861 break;862 case 'user':863 userArgs = argv.slice(0);864 break;865 default:866 throw new Error(`unexpected parse option { from: '${parseOptions.from}' }`);867 }868 if (!this._scriptPath && require.main) {869 this._scriptPath = require.main.filename;870 }871 872 // Guess name, used in usage in help.873 this._name = this._name || (this._scriptPath && path.basename(this._scriptPath, path.extname(this._scriptPath)));874 875 return userArgs;876 }877 878 /**879 * Parse `argv`, setting options and invoking commands when defined.880 *881 * The default expectation is that the arguments are from node and have the application as argv[0]882 * and the script being run in argv[1], with user parameters after that.883 *884 * @example885 * program.parse(process.argv);886 * program.parse(); // implicitly use process.argv and auto-detect node vs electron conventions887 * program.parse(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]888 *889 * @param {string[]} [argv] - optional, defaults to process.argv890 * @param {Object} [parseOptions] - optionally specify style of options with from: node/user/electron891 * @param {string} [parseOptions.from] - where the args are from: 'node', 'user', 'electron'892 * @return {Command} `this` command for chaining893 */894 895 parse(argv, parseOptions) {896 const userArgs = this._prepareUserArgs(argv, parseOptions);897 this._parseCommand([], userArgs);898 899 return this;900 };901 902 /**903 * Parse `argv`, setting options and invoking commands when defined.904 *905 * Use parseAsync instead of parse if any of your action handlers are async. Returns a Promise.906 *907 * The default expectation is that the arguments are from node and have the application as argv[0]908 * and the script being run in argv[1], with user parameters after that.909 *910 * @example911 * await program.parseAsync(process.argv);912 * await program.parseAsync(); // implicitly use process.argv and auto-detect node vs electron conventions913 * await program.parseAsync(my-args, { from: 'user' }); // just user supplied arguments, nothing special about argv[0]914 *915 * @param {string[]} [argv]916 * @param {Object} [parseOptions]917 * @param {string} parseOptions.from - where the args are from: 'node', 'user', 'electron'918 * @return {Promise}919 */920 921 async parseAsync(argv, parseOptions) {922 const userArgs = this._prepareUserArgs(argv, parseOptions);923 await this._parseCommand([], userArgs);924 925 return this;926 };927 928 /**929 * Execute a sub-command executable.930 *931 * @api private932 */933 934 _executeSubCommand(subcommand, args) {935 args = args.slice();936 let launchWithNode = false; // Use node for source targets so do not need to get permissions correct, and on Windows.937 const sourceExt = ['.js', '.ts', '.tsx', '.mjs', '.cjs'];938 939 // Not checking for help first. Unlikely to have mandatory and executable, and can't robustly test for help flags in external command.940 this._checkForMissingMandatoryOptions();941 942 // Want the entry script as the reference for command name and directory for searching for other files.943 let scriptPath = this._scriptPath;944 // Fallback in case not set, due to how Command created or called.945 if (!scriptPath && require.main) {946 scriptPath = require.main.filename;947 }948 949 let baseDir;950 try {951 const resolvedLink = fs.realpathSync(scriptPath);952 baseDir = path.dirname(resolvedLink);953 } catch (e) {954 baseDir = '.'; // dummy, probably not going to find executable!955 }956 957 // name of the subcommand, like `pm-install`958 let bin = path.basename(scriptPath, path.extname(scriptPath)) + '-' + subcommand._name;959 if (subcommand._executableFile) {960 bin = subcommand._executableFile;961 }962 963 const localBin = path.join(baseDir, bin);964 if (fs.existsSync(localBin)) {965 // prefer local `./<bin>` to bin in the $PATH966 bin = localBin;967 } else {968 // Look for source files.969 sourceExt.forEach((ext) => {970 if (fs.existsSync(`${localBin}${ext}`)) {971 bin = `${localBin}${ext}`;972 }973 });974 }975 launchWithNode = sourceExt.includes(path.extname(bin));976 977 let proc;978 if (process.platform !== 'win32') {979 if (launchWithNode) {980 args.unshift(bin);981 // add executable arguments to spawn982 args = incrementNodeInspectorPort(process.execArgv).concat(args);983 984 proc = childProcess.spawn(process.argv[0], args, { stdio: 'inherit' });985 } else {986 proc = childProcess.spawn(bin, args, { stdio: 'inherit' });987 }988 } else {989 args.unshift(bin);990 // add executable arguments to spawn991 args = incrementNodeInspectorPort(process.execArgv).concat(args);992 proc = childProcess.spawn(process.execPath, args, { stdio: 'inherit' });993 }994 995 const signals = ['SIGUSR1', 'SIGUSR2', 'SIGTERM', 'SIGINT', 'SIGHUP'];996 signals.forEach((signal) => {997 // @ts-ignore998 process.on(signal, () => {999 if (proc.killed === false && proc.exitCode === null) {1000 proc.kill(signal);1001 }1002 });1003 });1004 1005 // By default terminate process when spawned process terminates.1006 // Suppressing the exit if exitCallback defined is a bit messy and of limited use, but does allow process to stay running!1007 const exitCallback = this._exitCallback;1008 if (!exitCallback) {1009 proc.on('close', process.exit.bind(process));1010 } else {1011 proc.on('close', () => {1012 exitCallback(new CommanderError(process.exitCode || 0, 'commander.executeSubCommandAsync', '(close)'));1013 });1014 }1015 proc.on('error', (err) => {1016 // @ts-ignore1017 if (err.code === 'ENOENT') {1018 const executableMissing = `'${bin}' does not exist1019 - if '${subcommand._name}' is not meant to be an executable command, remove description parameter from '.command()' and use '.description()' instead1020 - if the default executable name is not suitable, use the executableFile option to supply a custom name`;1021 throw new Error(executableMissing);1022 // @ts-ignore1023 } else if (err.code === 'EACCES') {1024 throw new Error(`'${bin}' not executable`);1025 }1026 if (!exitCallback) {1027 process.exit(1);1028 } else {1029 const wrappedError = new CommanderError(1, 'commander.executeSubCommandAsync', '(error)');1030 wrappedError.nestedError = err;1031 exitCallback(wrappedError);1032 }1033 });1034 1035 // Store the reference to the child process1036 this.runningCommand = proc;1037 };1038 1039 /**1040 * @api private1041 */1042 1043 _dispatchSubcommand(commandName, operands, unknown) {1044 const subCommand = this._findCommand(commandName);1045 if (!subCommand) this.help({ error: true });1046 1047 if (subCommand._executableHandler) {1048 this._executeSubCommand(subCommand, operands.concat(unknown));1049 } else {1050 return subCommand._parseCommand(operands, unknown);1051 }1052 };1053 1054 /**1055 * Check this.args against expected this._args.1056 *1057 * @api private1058 */1059 1060 _checkNumberOfArguments() {1061 // too few1062 this._args.forEach((arg, i) => {1063 if (arg.required && this.args[i] == null) {1064 this.missingArgument(arg.name());1065 }1066 });1067 // too many1068 if (this._args.length > 0 && this._args[this._args.length - 1].variadic) {1069 return;1070 }1071 if (this.args.length > this._args.length) {1072 this._excessArguments(this.args);1073 }1074 };1075 1076 /**1077 * Process this.args using this._args and save as this.processedArgs!1078 *1079 * @api private1080 */1081 1082 _processArguments() {1083 const myParseArg = (argument, value, previous) => {1084 // Extra processing for nice error message on parsing failure.1085 let parsedValue = value;1086 if (value !== null && argument.parseArg) {1087 try {1088 parsedValue = argument.parseArg(value, previous);1089 } catch (err) {1090 if (err.code === 'commander.invalidArgument') {1091 const message = `error: command-argument value '${value}' is invalid for argument '${argument.name()}'. ${err.message}`;1092 this._displayError(err.exitCode, err.code, message);1093 }1094 throw err;1095 }1096 }1097 return parsedValue;1098 };1099 1100 this._checkNumberOfArguments();1101 1102 const processedArgs = [];1103 this._args.forEach((declaredArg, index) => {1104 let value = declaredArg.defaultValue;1105 if (declaredArg.variadic) {1106 // Collect together remaining arguments for passing together as an array.1107 if (index < this.args.length) {1108 value = this.args.slice(index);1109 if (declaredArg.parseArg) {1110 value = value.reduce((processed, v) => {1111 return myParseArg(declaredArg, v, processed);1112 }, declaredArg.defaultValue);1113 }1114 } else if (value === undefined) {1115 value = [];1116 }1117 } else if (index < this.args.length) {1118 value = this.args[index];1119 if (declaredArg.parseArg) {1120 value = myParseArg(declaredArg, value, declaredArg.defaultValue);1121 }1122 }1123 processedArgs[index] = value;1124 });1125 this.processedArgs = processedArgs;1126 }1127 1128 /**1129 * Once we have a promise we chain, but call synchronously until then.1130 *1131 * @param {Promise|undefined} promise1132 * @param {Function} fn1133 * @return {Promise|undefined}1134 * @api private1135 */1136 1137 _chainOrCall(promise, fn) {1138 // thenable1139 if (promise && promise.then && typeof promise.then === 'function') {1140 // already have a promise, chain callback1141 return promise.then(() => fn());1142 }1143 // callback might return a promise1144 return fn();1145 }1146 1147 /**1148 *1149 * @param {Promise|undefined} promise1150 * @param {string} event1151 * @return {Promise|undefined}1152 * @api private1153 */1154 1155 _chainOrCallHooks(promise, event) {1156 let result = promise;1157 const hooks = [];1158 getCommandAndParents(this)1159 .reverse()1160 .filter(cmd => cmd._lifeCycleHooks[event] !== undefined)1161 .forEach(hookedCommand => {1162 hookedCommand._lifeCycleHooks[event].forEach((callback) => {1163 hooks.push({ hookedCommand, callback });1164 });1165 });1166 if (event === 'postAction') {1167 hooks.reverse();1168 }1169 1170 hooks.forEach((hookDetail) => {1171 result = this._chainOrCall(result, () => {1172 return hookDetail.callback(hookDetail.hookedCommand, this);1173 });1174 });1175 return result;1176 }1177 1178 /**1179 * Process arguments in context of this command.1180 * Returns action result, in case it is a promise.1181 *1182 * @api private1183 */1184 1185 _parseCommand(operands, unknown) {1186 const parsed = this.parseOptions(unknown);1187 this._parseOptionsEnv(); // after cli, so parseArg not called on both cli and env1188 operands = operands.concat(parsed.operands);1189 unknown = parsed.unknown;1190 this.args = operands.concat(unknown);1191 1192 if (operands && this._findCommand(operands[0])) {1193 return this._dispatchSubcommand(operands[0], operands.slice(1), unknown);1194 }1195 if (this._hasImplicitHelpCommand() && operands[0] === this._helpCommandName) {1196 if (operands.length === 1) {1197 this.help();1198 }1199 return this._dispatchSubcommand(operands[1], [], [this._helpLongFlag]);1200 }