in src/CLIBase.hack [206:290]
public function __construct(
private vec<string> $argv,
private ITerminal $terminal,
) {
// Ignore process name in $argv[0]
$argv = Vec\drop($argv, 1);
$options = $this->getSupportedOptions();
$long_options =
Dict\pull($options, $opt ==> $opt, $opt ==> $opt->getLong());
$short_options = Vec\filter($options, $opt ==> $opt->getShort() !== null)
|> Dict\pull($$, $opt ==> $opt, $opt ==> (string)$opt->getShort());
$all_options = dict[
CLIOptions\CLIOptionType::LONG => $long_options,
CLIOptions\CLIOptionType::SHORT => $short_options,
];
$arguments = vec[];
while (!C\is_empty($argv)) {
$arg = C\firstx($argv);
$argv = Vec\drop($argv, 1);
if ($arg === '--help' || $arg === '-h') {
/* HHAST_IGNORE_ERROR[DontUseAsioJoin] */
\HH\Asio\join($this->displayHelpAsync($terminal->getStdout()));
throw new ExitException(0);
}
// standard 'stop parsing options here' marker
if ($arg === '--') {
break;
}
list($option_type, $option_value) =
CLIOptions\CLIOption::getTypeAndValue($arg);
if ($option_type === CLIOptions\CLIOptionType::ARGUMENT) {
$arguments[] = $arg;
if ((bool)\getenv('POSIXLY_CORRECT')) {
break;
}
continue;
}
$options = self::extractOptions($option_value, $option_type);
$available_options = $all_options[$option_type];
foreach ($options as $option => $value) {
if (!C\contains_key($available_options, $option)) {
throw new InvalidArgumentException('Unrecognized option: %s', $arg);
} else {
$argv = $available_options[$option]->apply($option, $value, $argv);
}
}
}
$arguments = Vec\concat($arguments, $argv);
if (C\is_empty($arguments)) {
if ($this is CLIWithRequiredArguments) {
$class = TypeAssert\classname_of(
CLIWithRequiredArguments::class,
static::class,
);
throw new InvalidArgumentException(
'%s must be specified.',
Str\join($class::getHelpTextForRequiredArguments(), ' '),
);
}
return;
}
if ($this is CLIWithArguments) {
$this->arguments = $arguments;
return;
}
throw new InvalidArgumentException(
"Non-option arguments are not supported; first argument is '%s'",
C\firstx($arguments),
);
}