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