11cb0ef41Sopenharmony_ci'use strict';
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ciconst {
41cb0ef41Sopenharmony_ci  ArrayPrototypeFind,
51cb0ef41Sopenharmony_ci  ObjectEntries,
61cb0ef41Sopenharmony_ci  ObjectPrototypeHasOwnProperty: ObjectHasOwn,
71cb0ef41Sopenharmony_ci  StringPrototypeCharAt,
81cb0ef41Sopenharmony_ci  StringPrototypeIncludes,
91cb0ef41Sopenharmony_ci  StringPrototypeStartsWith,
101cb0ef41Sopenharmony_ci} = require('./internal/primordials');
111cb0ef41Sopenharmony_ci
121cb0ef41Sopenharmony_ciconst {
131cb0ef41Sopenharmony_ci  validateObject,
141cb0ef41Sopenharmony_ci} = require('./internal/validators');
151cb0ef41Sopenharmony_ci
161cb0ef41Sopenharmony_ci// These are internal utilities to make the parsing logic easier to read, and
171cb0ef41Sopenharmony_ci// add lots of detail for the curious. They are in a separate file to allow
181cb0ef41Sopenharmony_ci// unit testing, although that is not essential (this could be rolled into
191cb0ef41Sopenharmony_ci// main file and just tested implicitly via API).
201cb0ef41Sopenharmony_ci//
211cb0ef41Sopenharmony_ci// These routines are for internal use, not for export to client.
221cb0ef41Sopenharmony_ci
231cb0ef41Sopenharmony_ci/**
241cb0ef41Sopenharmony_ci * Return the named property, but only if it is an own property.
251cb0ef41Sopenharmony_ci */
261cb0ef41Sopenharmony_cifunction objectGetOwn(obj, prop) {
271cb0ef41Sopenharmony_ci  if (ObjectHasOwn(obj, prop))
281cb0ef41Sopenharmony_ci    return obj[prop];
291cb0ef41Sopenharmony_ci}
301cb0ef41Sopenharmony_ci
311cb0ef41Sopenharmony_ci/**
321cb0ef41Sopenharmony_ci * Return the named options property, but only if it is an own property.
331cb0ef41Sopenharmony_ci */
341cb0ef41Sopenharmony_cifunction optionsGetOwn(options, longOption, prop) {
351cb0ef41Sopenharmony_ci  if (ObjectHasOwn(options, longOption))
361cb0ef41Sopenharmony_ci    return objectGetOwn(options[longOption], prop);
371cb0ef41Sopenharmony_ci}
381cb0ef41Sopenharmony_ci
391cb0ef41Sopenharmony_ci/**
401cb0ef41Sopenharmony_ci * Determines if the argument may be used as an option value.
411cb0ef41Sopenharmony_ci * @example
421cb0ef41Sopenharmony_ci * isOptionValue('V') // returns true
431cb0ef41Sopenharmony_ci * isOptionValue('-v') // returns true (greedy)
441cb0ef41Sopenharmony_ci * isOptionValue('--foo') // returns true (greedy)
451cb0ef41Sopenharmony_ci * isOptionValue(undefined) // returns false
461cb0ef41Sopenharmony_ci */
471cb0ef41Sopenharmony_cifunction isOptionValue(value) {
481cb0ef41Sopenharmony_ci  if (value == null) return false;
491cb0ef41Sopenharmony_ci
501cb0ef41Sopenharmony_ci  // Open Group Utility Conventions are that an option-argument
511cb0ef41Sopenharmony_ci  // is the argument after the option, and may start with a dash.
521cb0ef41Sopenharmony_ci  return true; // greedy!
531cb0ef41Sopenharmony_ci}
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci/**
561cb0ef41Sopenharmony_ci * Detect whether there is possible confusion and user may have omitted
571cb0ef41Sopenharmony_ci * the option argument, like `--port --verbose` when `port` of type:string.
581cb0ef41Sopenharmony_ci * In strict mode we throw errors if value is option-like.
591cb0ef41Sopenharmony_ci */
601cb0ef41Sopenharmony_cifunction isOptionLikeValue(value) {
611cb0ef41Sopenharmony_ci  if (value == null) return false;
621cb0ef41Sopenharmony_ci
631cb0ef41Sopenharmony_ci  return value.length > 1 && StringPrototypeCharAt(value, 0) === '-';
641cb0ef41Sopenharmony_ci}
651cb0ef41Sopenharmony_ci
661cb0ef41Sopenharmony_ci/**
671cb0ef41Sopenharmony_ci * Determines if `arg` is just a short option.
681cb0ef41Sopenharmony_ci * @example '-f'
691cb0ef41Sopenharmony_ci */
701cb0ef41Sopenharmony_cifunction isLoneShortOption(arg) {
711cb0ef41Sopenharmony_ci  return arg.length === 2 &&
721cb0ef41Sopenharmony_ci    StringPrototypeCharAt(arg, 0) === '-' &&
731cb0ef41Sopenharmony_ci    StringPrototypeCharAt(arg, 1) !== '-';
741cb0ef41Sopenharmony_ci}
751cb0ef41Sopenharmony_ci
761cb0ef41Sopenharmony_ci/**
771cb0ef41Sopenharmony_ci * Determines if `arg` is a lone long option.
781cb0ef41Sopenharmony_ci * @example
791cb0ef41Sopenharmony_ci * isLoneLongOption('a') // returns false
801cb0ef41Sopenharmony_ci * isLoneLongOption('-a') // returns false
811cb0ef41Sopenharmony_ci * isLoneLongOption('--foo') // returns true
821cb0ef41Sopenharmony_ci * isLoneLongOption('--foo=bar') // returns false
831cb0ef41Sopenharmony_ci */
841cb0ef41Sopenharmony_cifunction isLoneLongOption(arg) {
851cb0ef41Sopenharmony_ci  return arg.length > 2 &&
861cb0ef41Sopenharmony_ci    StringPrototypeStartsWith(arg, '--') &&
871cb0ef41Sopenharmony_ci    !StringPrototypeIncludes(arg, '=', 3);
881cb0ef41Sopenharmony_ci}
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci/**
911cb0ef41Sopenharmony_ci * Determines if `arg` is a long option and value in the same argument.
921cb0ef41Sopenharmony_ci * @example
931cb0ef41Sopenharmony_ci * isLongOptionAndValue('--foo') // returns false
941cb0ef41Sopenharmony_ci * isLongOptionAndValue('--foo=bar') // returns true
951cb0ef41Sopenharmony_ci */
961cb0ef41Sopenharmony_cifunction isLongOptionAndValue(arg) {
971cb0ef41Sopenharmony_ci  return arg.length > 2 &&
981cb0ef41Sopenharmony_ci    StringPrototypeStartsWith(arg, '--') &&
991cb0ef41Sopenharmony_ci    StringPrototypeIncludes(arg, '=', 3);
1001cb0ef41Sopenharmony_ci}
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci/**
1031cb0ef41Sopenharmony_ci * Determines if `arg` is a short option group.
1041cb0ef41Sopenharmony_ci *
1051cb0ef41Sopenharmony_ci * See Guideline 5 of the [Open Group Utility Conventions](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap12.html).
1061cb0ef41Sopenharmony_ci *   One or more options without option-arguments, followed by at most one
1071cb0ef41Sopenharmony_ci *   option that takes an option-argument, should be accepted when grouped
1081cb0ef41Sopenharmony_ci *   behind one '-' delimiter.
1091cb0ef41Sopenharmony_ci * @example
1101cb0ef41Sopenharmony_ci * isShortOptionGroup('-a', {}) // returns false
1111cb0ef41Sopenharmony_ci * isShortOptionGroup('-ab', {}) // returns true
1121cb0ef41Sopenharmony_ci * // -fb is an option and a value, not a short option group
1131cb0ef41Sopenharmony_ci * isShortOptionGroup('-fb', {
1141cb0ef41Sopenharmony_ci *   options: { f: { type: 'string' } }
1151cb0ef41Sopenharmony_ci * }) // returns false
1161cb0ef41Sopenharmony_ci * isShortOptionGroup('-bf', {
1171cb0ef41Sopenharmony_ci *   options: { f: { type: 'string' } }
1181cb0ef41Sopenharmony_ci * }) // returns true
1191cb0ef41Sopenharmony_ci * // -bfb is an edge case, return true and caller sorts it out
1201cb0ef41Sopenharmony_ci * isShortOptionGroup('-bfb', {
1211cb0ef41Sopenharmony_ci *   options: { f: { type: 'string' } }
1221cb0ef41Sopenharmony_ci * }) // returns true
1231cb0ef41Sopenharmony_ci */
1241cb0ef41Sopenharmony_cifunction isShortOptionGroup(arg, options) {
1251cb0ef41Sopenharmony_ci  if (arg.length <= 2) return false;
1261cb0ef41Sopenharmony_ci  if (StringPrototypeCharAt(arg, 0) !== '-') return false;
1271cb0ef41Sopenharmony_ci  if (StringPrototypeCharAt(arg, 1) === '-') return false;
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  const firstShort = StringPrototypeCharAt(arg, 1);
1301cb0ef41Sopenharmony_ci  const longOption = findLongOptionForShort(firstShort, options);
1311cb0ef41Sopenharmony_ci  return optionsGetOwn(options, longOption, 'type') !== 'string';
1321cb0ef41Sopenharmony_ci}
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci/**
1351cb0ef41Sopenharmony_ci * Determine if arg is a short string option followed by its value.
1361cb0ef41Sopenharmony_ci * @example
1371cb0ef41Sopenharmony_ci * isShortOptionAndValue('-a', {}); // returns false
1381cb0ef41Sopenharmony_ci * isShortOptionAndValue('-ab', {}); // returns false
1391cb0ef41Sopenharmony_ci * isShortOptionAndValue('-fFILE', {
1401cb0ef41Sopenharmony_ci *   options: { foo: { short: 'f', type: 'string' }}
1411cb0ef41Sopenharmony_ci * }) // returns true
1421cb0ef41Sopenharmony_ci */
1431cb0ef41Sopenharmony_cifunction isShortOptionAndValue(arg, options) {
1441cb0ef41Sopenharmony_ci  validateObject(options, 'options');
1451cb0ef41Sopenharmony_ci
1461cb0ef41Sopenharmony_ci  if (arg.length <= 2) return false;
1471cb0ef41Sopenharmony_ci  if (StringPrototypeCharAt(arg, 0) !== '-') return false;
1481cb0ef41Sopenharmony_ci  if (StringPrototypeCharAt(arg, 1) === '-') return false;
1491cb0ef41Sopenharmony_ci
1501cb0ef41Sopenharmony_ci  const shortOption = StringPrototypeCharAt(arg, 1);
1511cb0ef41Sopenharmony_ci  const longOption = findLongOptionForShort(shortOption, options);
1521cb0ef41Sopenharmony_ci  return optionsGetOwn(options, longOption, 'type') === 'string';
1531cb0ef41Sopenharmony_ci}
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci/**
1561cb0ef41Sopenharmony_ci * Find the long option associated with a short option. Looks for a configured
1571cb0ef41Sopenharmony_ci * `short` and returns the short option itself if a long option is not found.
1581cb0ef41Sopenharmony_ci * @example
1591cb0ef41Sopenharmony_ci * findLongOptionForShort('a', {}) // returns 'a'
1601cb0ef41Sopenharmony_ci * findLongOptionForShort('b', {
1611cb0ef41Sopenharmony_ci *   options: { bar: { short: 'b' } }
1621cb0ef41Sopenharmony_ci * }) // returns 'bar'
1631cb0ef41Sopenharmony_ci */
1641cb0ef41Sopenharmony_cifunction findLongOptionForShort(shortOption, options) {
1651cb0ef41Sopenharmony_ci  validateObject(options, 'options');
1661cb0ef41Sopenharmony_ci  const longOptionEntry = ArrayPrototypeFind(
1671cb0ef41Sopenharmony_ci    ObjectEntries(options),
1681cb0ef41Sopenharmony_ci    ({ 1: optionConfig }) => objectGetOwn(optionConfig, 'short') === shortOption
1691cb0ef41Sopenharmony_ci  );
1701cb0ef41Sopenharmony_ci  return longOptionEntry?.[0] ?? shortOption;
1711cb0ef41Sopenharmony_ci}
1721cb0ef41Sopenharmony_ci
1731cb0ef41Sopenharmony_ci/**
1741cb0ef41Sopenharmony_ci * Check if the given option includes a default value
1751cb0ef41Sopenharmony_ci * and that option has not been set by the input args.
1761cb0ef41Sopenharmony_ci *
1771cb0ef41Sopenharmony_ci * @param {string} longOption - long option name e.g. 'foo'
1781cb0ef41Sopenharmony_ci * @param {object} optionConfig - the option configuration properties
1791cb0ef41Sopenharmony_ci * @param {object} values - option values returned in `values` by parseArgs
1801cb0ef41Sopenharmony_ci */
1811cb0ef41Sopenharmony_cifunction useDefaultValueOption(longOption, optionConfig, values) {
1821cb0ef41Sopenharmony_ci  return objectGetOwn(optionConfig, 'default') !== undefined &&
1831cb0ef41Sopenharmony_ci    values[longOption] === undefined;
1841cb0ef41Sopenharmony_ci}
1851cb0ef41Sopenharmony_ci
1861cb0ef41Sopenharmony_cimodule.exports = {
1871cb0ef41Sopenharmony_ci  findLongOptionForShort,
1881cb0ef41Sopenharmony_ci  isLoneLongOption,
1891cb0ef41Sopenharmony_ci  isLoneShortOption,
1901cb0ef41Sopenharmony_ci  isLongOptionAndValue,
1911cb0ef41Sopenharmony_ci  isOptionValue,
1921cb0ef41Sopenharmony_ci  isOptionLikeValue,
1931cb0ef41Sopenharmony_ci  isShortOptionAndValue,
1941cb0ef41Sopenharmony_ci  isShortOptionGroup,
1951cb0ef41Sopenharmony_ci  useDefaultValueOption,
1961cb0ef41Sopenharmony_ci  objectGetOwn,
1971cb0ef41Sopenharmony_ci  optionsGetOwn,
1981cb0ef41Sopenharmony_ci};
199