Skip to content

Commit

Permalink
Refactor parseOptions()
Browse files Browse the repository at this point in the history
Eliminates redundant calls and checks.

(cherry picked from commit dd2c9c8)
  • Loading branch information
aweebit committed Aug 7, 2023
1 parent d038570 commit d7e2399
Showing 1 changed file with 66 additions and 50 deletions.
116 changes: 66 additions & 50 deletions lib/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -1439,12 +1439,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
let dest = operands;
const args = argv.slice();

function maybeOption(arg) {
return arg.length > 1 && arg[0] === '-';
}

// parse options
let activeVariadicOption = null;
let onlyKnownOptionsSoFar = true;
while (args.length) {
const arg = args.shift();

Expand All @@ -1455,13 +1452,15 @@ Expecting one of '${allowedValues.join("', '")}'`);
break;
}

if (activeVariadicOption && !maybeOption(arg)) {
const isArgFlag = isFlag(arg);

if (activeVariadicOption && !isArgFlag) {
this.emit(`option:${activeVariadicOption.name()}`, arg);
continue;
}
activeVariadicOption = null;

if (maybeOption(arg)) {
if (isArgFlag) {
const option = this._findOption(arg);
// recognised option, call listener to assign value with possible custom processing
if (option) {
Expand All @@ -1472,7 +1471,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
} else if (option.optional) {
let value = null;
// historical behaviour is optional value is following arg unless an option
if (args.length > 0 && !maybeOption(args[0])) {
if (args.length > 0 && !isFlag(args[0])) {
value = args.shift();
}
this.emit(`option:${option.name()}`, value);
Expand All @@ -1482,63 +1481,70 @@ Expecting one of '${allowedValues.join("', '")}'`);
activeVariadicOption = option.variadic ? option : null;
continue;
}
}

// Look for combo options following single dash, eat first one if known.
if (arg.length > 2 && arg[0] === '-' && arg[1] !== '-') {
const option = this._findOption(`-${arg[1]}`);
if (option) {
if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
// option with value following in same argument
this.emit(`option:${option.name()}`, arg.slice(2));
} else {
// boolean option, emit and put back remainder of arg for further processing
this.emit(`option:${option.name()}`);
args.unshift(`-${arg.slice(2)}`);
// Look for combo options following single dash, eat first one if known.
if (arg.length > 2 && arg[1] !== '-') {
const option = this._findOption(`-${arg[1]}`);
if (option) {
if (option.required || (option.optional && this._combineFlagAndOptionalValue)) {
// option with value following in same argument
this.emit(`option:${option.name()}`, arg.slice(2));
} else {
// boolean option, emit and put back remainder of arg for further processing
this.emit(`option:${option.name()}`);
args.unshift(`-${arg.slice(2)}`);
}
continue;
}
continue;
}
}

// Look for known long flag with value, like --foo=bar
if (/^--[^=]+=/.test(arg)) {
const index = arg.indexOf('=');
const option = this._findOption(arg.slice(0, index));
if (option && (option.required || option.optional)) {
this.emit(`option:${option.name()}`, arg.slice(index + 1));
continue;
// Look for known long flag with value, like --foo=bar
if (/^--[^=]+=/.test(arg)) {
const index = arg.indexOf('=');
const option = this._findOption(arg.slice(0, index));
if (option && (option.required || option.optional)) {
this.emit(`option:${option.name()}`, arg.slice(index + 1));
continue;
}
}
}

// Not a recognised option by this command.
// Might be a command-argument, or subcommand option, or unknown option, or help command or option.
// Not a recognised option by this command. Might be
// - a subcommand,
// - an option unknown to this command,
// - or a command-argument.

if (onlyKnownOptionsSoFar) {
const stopAtSubcommand = (
this._enablePositionalOptions || this._passThroughOptions
);
if (stopAtSubcommand) {
if (!isArgFlag && this._findCommand(arg)) {
operands.push(arg);
unknown.push(...args);
break;
} else if (!isArgFlag &&
arg === this._helpCommandName &&
this._hasImplicitHelpCommand()
) {
operands.push(arg, ...args);
break;
} else if (this._defaultCommandName) {
unknown.push(arg, ...args);
break;
}
}
}
onlyKnownOptionsSoFar = false;

// An unknown option means further arguments also classified as unknown so can be reprocessed by subcommands.
if (maybeOption(arg)) {
if (isArgFlag) {
dest = unknown;
}

// If using positionalOptions, stop processing our options at subcommand.
if ((this._enablePositionalOptions || this._passThroughOptions) && operands.length === 0 && unknown.length === 0) {
if (this._findCommand(arg)) {
operands.push(arg);
if (args.length > 0) unknown.push(...args);
break;
} else if (arg === this._helpCommandName && this._hasImplicitHelpCommand()) {
operands.push(arg);
if (args.length > 0) operands.push(...args);
break;
} else if (this._defaultCommandName) {
unknown.push(arg);
if (args.length > 0) unknown.push(...args);
break;
}
}

// If using passThroughOptions, stop processing options at first command-argument.
if (this._passThroughOptions) {
dest.push(arg);
if (args.length > 0) dest.push(...args);
dest.push(arg, ...args);
break;
}

Expand Down Expand Up @@ -2193,4 +2199,14 @@ function getCommandAndParents(startCommand) {
return result;
}

/**
* @param {string} arg
* @returns {boolean}
* @api private
*/

function isFlag(arg) {
return arg.length > 1 && arg[0] === '-';
}

exports.Command = Command;

0 comments on commit d7e2399

Please sign in to comment.