From 1ae63aa5174d886568fdbc2c20eeda0c989703ab Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Wed, 9 Sep 2020 17:21:49 -0700 Subject: [PATCH 01/14] util: add util.parseArgs() Add a function, `util.parseArgs()`, which accepts an array of arguments and returns a parsed object representation thereof. Ref: https://github.com/nodejs/tooling/issues/19 --- doc/api/util.md | 103 +++++++++++++++ lib/internal/util/parse_args.js | 121 ++++++++++++++++++ lib/util.js | 2 + node.gyp | 1 + test/parallel/test-bootstrap-modules.js | 1 + test/parallel/test-util-parseargs.js | 160 ++++++++++++++++++++++++ 6 files changed, 388 insertions(+) create mode 100644 lib/internal/util/parse_args.js create mode 100644 test/parallel/test-util-parseargs.js diff --git a/doc/api/util.md b/doc/api/util.md index 6b857a027f39ef..b6758a345a59fc 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -946,6 +946,107 @@ Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv[, options]])` + + +* `argv` {Array|Object} (Optional) Array of argument strings; defaults + to [`process.argv.slice(2)`](process_argv). If an Object, the default is used, + and this parameter is considered to be the `options` parameter. +* `options` {Object} (Optional) The `options` parameter, if present, is an + object supporting the following property: + * `expectsValue` {Array|string} (Optional) One or more argument + strings which _expect a value_ when present +* Returns: {Object} An object having properties corresponding to parsed Options + and Flags, and a property `_` containing Positionals + +The `util.parseArgs` function parses command-line arguments from an array of +strings and returns an object representation. + +Example using [`process.argv`][]: + +```js +// script.js +// called via `node script.js --foo bar baz` +const argv = util.parseArgs(); + +// argv.foo === true +if (argv.foo) { + console.log(argv._); // prints [ 'bar', 'baz' ] +} +``` + +Example using a custom `argv` and the `expectsValue` option: + +```js +const argv = util.parseArgs( + ['--foo', 'bar', 'baz'], + { expectsValue: ['foo'] } +); + +// argv.foo === 'bar' +if (argv.foo === 'bar') { + console.log(argv._); // prints [ 'baz' ] +} +``` + +[`ERR_INVALID_ARG_TYPE`][] will be thrown if the `argv` parameter is not an +Array. + +Arguments fall into one of three catgories: + +* _Flags_, which begin with one or more dashes (`-`), and _do not_ have an + associated string value (e.g., `node app.js --verbose`) + * These will be parsed automatically; you do not need to "declare" them + * The Flag _name_ is the string following the prefix of one-or-more dashes, + e.g., the name of `--foo` is `foo` + * Flag names become property names in the returned object + * When appearing _once_ in the array, the value of the property will be `true` + * When _repeated_ in the array, the value of the property becomes a count of + repetitions (e.g., `['-v', '-v' '-v']` results in `{ v: 3 }`) +* _Options_, declared by `expectsValue`, which begin with one or more dashes, + and _do_ have an associated value (e.g., `node app.js --require script.js`) + * Use the `expectsValue` option to `util.parseArgs` to declare Options + * The Option _name_ is the string following the prefix of one-or-more dashes, + e.g., the name of `--foo` is `foo` + * The Option _value_ is the next string following the name, e.g., the Option + value of `['--foo' 'bar']` is `bar` + * Option values may be provided _with or without_ a `=` separator (e.g., + `['--require=script.js']` is equivalent to `['--require', 'script.js']`) + * An Option value is considered "missing" and is results in `true` when: + * A `=` does not separate the Option name from its value (e.g., `--foo bar`) + _and_ the following argument begins with a dash (e.g., `['--foo', + '--bar']`), _OR_ + * The array ends with the Option name (e.g., `['--foo']`) + * When repeated, values are concatenated into an Array; unlike Flags, they _do + not_ become a numeric count + * When an Option name appears in the Array (or string) of `expectsValue`, and + does _not_ appear in the `argv` array, the resulting object _will not_ + contain a property with this Option name (e.g., + `util.parseArgs(['--bar'], { expectsValue: 'foo' })` will result in + `{bar: true, _: [] }` +* _Positionals_ (or "positional arguments"), which _do not_ begin with one or + more dashes (e.g., `['script.js']`), _or_ every item in the `argv` Array + following a `--` (e.g., `['--', 'script.js']`) + * Positionals appear in the Array property `_` of the returned object + * The `_` property will _always_ be present and an Array, even if empty + * If present in the `argv` Array, `--` is discarded and is omitted from the + returned object + * Positionals will _always_ be parsed verbatim (e.g., `['--', '--foo']` will + result in an object of `{_: ['--foo']}`) + +A Flag or Option with having the name `_` will be ignored. If it was declared +as an Option (via the `expectsValue` option), its value will be ignored as well. + +`util.parseArgs` does not consider "short" arguments (e.g., `-v`) to be +different than "long" arguments (e.g., `--verbose`). Furthermore, it does not +allow concatenation of short arguments (e.g., `-v -D` cannot be expressed as +`-vD`). + +Conversion to/from "camelCase" occurs; a Flag or Option name of `no-color` +results in an object with a `no-color` property. + ## `util.promisify(original)` -* `argv` {Array|Object} (Optional) Array of argument strings; defaults +* `argv` {string[]|Object} (Optional) Array of argument strings; defaults to [`process.argv.slice(2)`](process_argv). If an Object, the default is used, and this parameter is considered to be the `options` parameter. * `options` {Object} (Optional) The `options` parameter, if present, is an - object supporting the following property: - * `optionsWithValue` {Array|string} (Optional) One or more argument - strings which _expect a value_ when present - * `multiOptions` {Array|string} (Optional) One or more argument - strings which can be appear multiple times in `argv` and will be - concatenated into an array + object supporting the following properties: + * `optionsWithValue` {string[]|string} (Optional) One or more argument + strings which _expect a value_ when present (see [Options][] + for details) + * `multiOptions` {string[]|string} (Optional) One or more argument + strings which, when appearing multiple times in `argv`, will be concatenated + into an Array * Returns: {Object} An object having properties: - * `options`, an Object with properties and values corresponding to parsed - Options and Flags - * `positionals`, an Array containing containing Positionals + * `options` {Object}, having properties and values corresponding to parsed + [Options][] and [Flags][], if any + * `positionals` {string[]}, containing [Positionals][], if any -The `util.parseArgs` function parses command-line arguments from an array of +The `util.parseArgs` function parses command-line arguments from an Array of strings and returns an object representation. Example using [`process.argv`][]: @@ -976,8 +977,7 @@ Example using [`process.argv`][]: // called via `node script.js --foo bar baz` const argv = util.parseArgs(); -// argv.foo === true -if (argv.foo) { +if (argv.foo === true) { console.log(argv.positionals); // prints [ 'bar', 'baz' ] } ``` @@ -1007,62 +1007,95 @@ const argv = util.parseArgs( console.log(argv.options.bar); // prints [ 'bar', 'baz' ] ``` +Example with custom `argv` and `multiOptions`: + +```js +const argv = util.parseArgs( + ['-v', '-v', '-v'], + { multiOptions: 'v' } +); + +console.log(argv.options.v); // prints [ true, true, true ] +``` + [`ERR_INVALID_ARG_TYPE`][] will be thrown if the `argv` parameter is not an Array. Arguments fall into one of three catgories: -* _Flags_, which begin with one or more dashes (`-`), and _do not_ have an - associated string value (e.g., `node app.js --verbose`) - * These will be parsed automatically; you do not need to "declare" them - * The Flag _name_ is the string following the prefix of one-or-more dashes, - e.g., the name of `--foo` is `foo` - * Flag names become property names in the returned object - * When appearing _once_ in the array, the value of the property will be `true` - * When _repeated_ in the array, the value of the property becomes a count of - repetitions (e.g., `['-v', '-v' '-v']` results in `{ v: 3 }`) -* _Options_, declared by `optionsWithValue`, which begin with one or more - dashes, and _do_ have an associated value (e.g., `node app.js --require - script.js`) - * Use the `optionsWithValue` option to `util.parseArgs` to declare Options - * The Option _name_ is the string following the prefix of one-or-more dashes, - e.g., the name of `--foo` is `foo` - * The Option _value_ is the next string following the name, e.g., the Option - value of `['--foo' 'bar']` is `bar` - * Option values may be provided _with or without_ a `=` separator (e.g., - `['--require=script.js']` is equivalent to `['--require', 'script.js']`) - * An Option value is considered "missing" and is results in `true` when: - * A `=` does not separate the Option name from its value (e.g., `--foo bar`) - _and_ the following argument begins with a dash (e.g., `['--foo', - '--bar']`), _OR_ - * The array ends with the Option name (e.g., `['--foo']`) - * When repeated, values are concatenated into an Array; unlike Flags, they _do - not_ become a numeric count - * When an Option name appears in the Array (or string) of `optionsWithValue`, - and does _not_ appear in the `argv` array, the resulting object _will not_ - contain a property with this Option name (e.g., `util.parseArgs(['--bar'], - { optionsWithValue: 'foo' })` will result in `{bar: true, _: [] }` -* _Positionals_ (or "positional arguments"), which _do not_ begin with one or - more dashes (e.g., `['script.js']`), _or_ every item in the `argv` Array - following a `--` (e.g., `['--', 'script.js']`) - * Positionals appear in the Array property `_` of the returned object - * The `_` property will _always_ be present and an Array, even if empty - * If present in the `argv` Array, `--` is discarded and is omitted from the - returned object - * Positionals will _always_ be parsed verbatim (e.g., `['--', '--foo']` will - result in an object of `{_: ['--foo']}`) - -A Flag or Option having the name `_` will be ignored. If it was declared as an -Option (via the `optionsWithValue` option), its value will be ignored as well. - -`util.parseArgs` does not consider "short" arguments (e.g., `-v`) to be -different than "long" arguments (e.g., `--verbose`). Furthermore, it does not -allow concatenation of short arguments (e.g., `-v -D` cannot be expressed as -`-vD`). - -_No_ conversion to/from "camelCase" occurs; a Flag or Option name of `no-color` -results in an object with a `no-color` property. A Flag or Option name of -`noColor` results in an object with a `noColor` property. +### Flags + +_Flags_ are arguments which begin with one or more dashes (`-`), and _do not_ +have an associated string value (e.g., `node app.js --verbose`). + +* These will be parsed automatically; you do not need to "declare" them +* The Flag _name_ is the string following the prefix of _one or more_ dashes, + e.g., the name of `--foo` is `foo` +* Flag names become property names in the `options` property of the returned + object +* By default, when appearing any number of times in the `argv` Array, the value + of the property will be `true`. To get a "count" of the times a Flag is + repeated, specify the Flag name in the `multiOptions` option; this will parsed + to an Array of `true` values, and you can derive the "count" from the `length` + property of this Array +* When a Flag appears in `multiOptions`, and when provided in `argv`, the value + in the returned object will _always_ be an Array (even if it is only provided + once) +* A Flag appearing in `multiOptions` but not in the `argv` Array will be omitted + from the `options` property of the returned object + +### Options + +_Options_ are arguments which begin with one or more dashes (`-`), and _do_ have +an associated value (e.g., `node app.js --require script.js`). + +* Use the `optionsWithValue` option to `util.parseArgs` to declare Options +* The Option _name_ is the string following the prefix of one-or-more dashes, + e.g., the name of `--foo` is `foo` +* The Option _value_ is the next string following the name, e.g., the Option + value of `['--foo' 'bar']` is `bar` +* Option values may be provided _with or without_ a `=` separator (e.g., + `['--require=script.js']` is equivalent to `['--require', 'script.js']`) +* If an Option value is not provided, the Option will be omitted from the + `options` property of the returned object +* An argument-like value (a value beginning with one or more dashes) immediately + following an Option in the `argv` Array will cause the Option to be omitted + from the `options` property of the returned object _unless_ the `=` separator + is used; e.g., `['--foo', '--bar']` where `foo` is an Option will return + `{options: {bar: true}, positionals: []}`, but `['--foo=--bar']` will return + `{options: {foo: '--bar'}, positionals: []}` +* When an Option name appears in the Array (or string) of `optionsWithValue`, + and does _not_ appear in the `argv` Array, the resulting object _will not_ + contain a property with this Option name (e.g., `util.parseArgs(['--bar'], { + optionsWithValue: 'foo' })` will result in `{options: {bar: true}, + positionals: [] }` +* When an Option appears in `multiOptions`, and when provided in `argv`, the + value in the returned object will _always_ be an Array (even if it is only + provided once) + +### Positionals + +_Positionals_ (or "positional arguments") are arguments which _do not_ begin +with one or more dashes (e.g., `['script.js']`), _and/or_ all items in the +`argv` Array following a `--` (e.g., `['--', 'script.js']`). + +* Positionals appear in the Array property `positionals` of the returned object +* The `positionals` property will _always_ be present and an Array, even if + empty +* If present in the `argv` Array, `--` is discarded and is omitted from the + returned object +* Positionals will _always_ be parsed verbatim (e.g., `['--', '--foo']` will + result in an object of `{positionals: ['--foo'], options: {}}`) + +Please note: + +* `util.parseArgs` does not consider "short" arguments (e.g., `-v`) to be + different than "long" arguments (e.g., `--verbose`). Furthermore, it does not + allow concatenation of short arguments (e.g., `-v -D` cannot be expressed as + `-vD`). +* _No_ conversion to or from "camelCase" occurs; a Flag or Option name of + `no-color` results in an object with a `no-color` property. A Flag or Option + name of `noColor` results in an object with a `noColor` property. ## `util.promisify(original)` @@ -954,18 +954,18 @@ added: REPLACEME * `argv` {string[]|Object} (Optional) Array of argument strings; defaults to [`process.argv.slice(2)`](process_argv). If an Object, the default is used, and this parameter is considered to be the `options` parameter. -* `options` {Object} (Optional) The `options` parameter, if present, is an +* `options` {Object} (Optional) The `options` parameter is an object supporting the following properties: * `optionsWithValue` {string[]|string} (Optional) One or more argument - strings which _expect a value_ when present (see [Options][] + strings which _expect a value_ when present in `argv` (see [Options][] for details) * `multiOptions` {string[]|string} (Optional) One or more argument strings which, when appearing multiple times in `argv`, will be concatenated into an Array * Returns: {Object} An object having properties: * `options` {Object}, having properties and values corresponding to parsed - [Options][] and [Flags][], if any - * `positionals` {string[]}, containing [Positionals][], if any + [Options][] and [Flags][] + * `positionals` {string[]}, containing [Positionals][] The `util.parseArgs` function parses command-line arguments from an Array of strings and returns an object representation. From d64e82aac326feb6288a25aa3d8799c8bf1daa2a Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 11 Sep 2020 12:05:33 -0700 Subject: [PATCH 09/14] docstring tweaks --- lib/internal/util/parse_args.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/internal/util/parse_args.js b/lib/internal/util/parse_args.js index 787b5ab8aac6c1..df687bfedb2166 100644 --- a/lib/internal/util/parse_args.js +++ b/lib/internal/util/parse_args.js @@ -22,9 +22,9 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; * - Argument(s) specified in `opts.optionsWithValue` will have `string` values * instead of `true`; the subsequent item in the `argv` array will be consumed * if a `=` is not used - * - "Bare" arguments are those which do not begin with a `-` or `--` and those - * after a bare `--`; these will be returned as items of the `positionals` - * array + * - "Bare" arguments (positionals) are those which do not begin with a `-` or + * `--` and those after a bare `--`; these will be returned as items of the + * `positionals` array * - The `positionals` array will always be present, even if empty. * - The `options` Object will always be present, even if empty. * @param {string[]} [argv=process.argv.slice(2)] - Array of script arguments as @@ -64,6 +64,8 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; * // {options: {foo: true}, positionals: []} * parseArgs(['--foo', '--foo'], {multiOptions: ['foo']}) * // {options: {foo: [true, true]}, positionals: []} + * parseArgs(['--very-wordy-option']) + * // {options: {'very-wordy-option': true}, positionals: []} */ const parseArgs = ( argv = ArrayPrototypeSlice(process.argv, 2), From 4dbdca31b8056b40949cbc0cb6db91182454515e Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Fri, 11 Sep 2020 12:10:45 -0700 Subject: [PATCH 10/14] add note about Flags dropping string values --- doc/api/util.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/api/util.md b/doc/api/util.md index 68c2b1f59b8a02..2db13c4117c92a 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1043,6 +1043,10 @@ have an associated string value (e.g., `node app.js --verbose`). once) * A Flag appearing in `multiOptions` but not in the `argv` Array will be omitted from the `options` property of the returned object +* If a string value is erroneously provided in `argv` for a Flag via the `=` + separator, the string value will be replaced with `true`; e.g., + `['--require=script.js']` becomes `{options: {require: true}}, positionals: + []}` ### Options From 97f7e88a68cd487ac9b95c811ceec7c0dd8cb0a2 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Mon, 14 Sep 2020 14:48:13 -0700 Subject: [PATCH 11/14] review updates --- doc/api/util.md | 10 +++++----- lib/internal/util/parse_args.js | 21 ++++++++++----------- test/parallel/test-util-parseargs.js | 4 ++++ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index 2db13c4117c92a..065eb80f45d27e 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1035,9 +1035,9 @@ have an associated string value (e.g., `node app.js --verbose`). object * By default, when appearing any number of times in the `argv` Array, the value of the property will be `true`. To get a "count" of the times a Flag is - repeated, specify the Flag name in the `multiOptions` option; this will parsed - to an Array of `true` values, and you can derive the "count" from the `length` - property of this Array + repeated, specify the Flag name in the `multiOptions` option; this will be + parsed to an Array of `true` values, and you can derive the "count" from the + `length` property of this Array * When a Flag appears in `multiOptions`, and when provided in `argv`, the value in the returned object will _always_ be an Array (even if it is only provided once) @@ -1050,7 +1050,7 @@ have an associated string value (e.g., `node app.js --verbose`). ### Options -_Options_ are arguments which begin with one or more dashes (`-`), and _do_ have +_Options_ are arguments which begin with one or more dashes (`-`), and _expect_ an associated value (e.g., `node app.js --require script.js`). * Use the `optionsWithValue` option to `util.parseArgs` to declare Options @@ -1091,7 +1091,7 @@ with one or more dashes (e.g., `['script.js']`), _and/or_ all items in the * Positionals will _always_ be parsed verbatim (e.g., `['--', '--foo']` will result in an object of `{positionals: ['--foo'], options: {}}`) -Please note: +### Additional Considerations * `util.parseArgs` does not consider "short" arguments (e.g., `-v`) to be different than "long" arguments (e.g., `--verbose`). Furthermore, it does not diff --git a/lib/internal/util/parse_args.js b/lib/internal/util/parse_args.js index df687bfedb2166..76ee5799e498d9 100644 --- a/lib/internal/util/parse_args.js +++ b/lib/internal/util/parse_args.js @@ -30,11 +30,11 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; * @param {string[]} [argv=process.argv.slice(2)] - Array of script arguments as * strings * @param {Object} [options] - Options - * @param {string[]|string} [opts.optionsWithValue] - This argument (or + * @param {string[]|string} [options.optionsWithValue] - This argument (or * arguments) expect a value - * @param {string[]|string} [opts.multiOptions] - This argument (or arguments) - * can be specified multiple times and its values will be concatenated into an - * array + * @param {string[]|string} [options.multiOptions] - This argument (or + * arguments) can be specified multiple times and its values will be + * concatenated into an array * @returns {{options: Object, positionals: string[]}} Parsed arguments * @example * parseArgs(['--foo', '--bar']) @@ -92,11 +92,8 @@ const parseArgs = ( const result = { positionals: [], options: {} }; let pos = 0; - while (true) { + while (pos < argv.length) { const arg = argv[pos]; - if (arg === undefined) { - return result; - } if (StringPrototypeStartsWith(arg, '-')) { // Everything after a bare '--' is considered a positional argument // and is returned verbatim @@ -115,8 +112,9 @@ const parseArgs = ( // and the next item is not itself a flag or option if (optionsWithValue.has(optionName)) { if (optionValue === undefined) { - optionValue = StringPrototypeStartsWith(argv[pos + 1], '-') || - argv[++pos]; + optionValue = ( + argv[pos + 1] && StringPrototypeStartsWith(argv[pos + 1], '-') + ) || argv[++pos]; } } else { optionValue = true; @@ -130,7 +128,7 @@ const parseArgs = ( } else { ArrayPrototypePush(result.options[optionName], optionValue); } - } else { + } else if (optionValue !== undefined) { result.options[optionName] = optionValue; } } else { @@ -138,6 +136,7 @@ const parseArgs = ( } pos++; } + return result; }; module.exports = { diff --git a/test/parallel/test-util-parseargs.js b/test/parallel/test-util-parseargs.js index c516f0b280b9a4..186272e006fe81 100644 --- a/test/parallel/test-util-parseargs.js +++ b/test/parallel/test-util-parseargs.js @@ -145,6 +145,10 @@ const { format, parseArgs } = require('util'); [ { argv: [], opts: { multiOptions: 'foo' } }, { options: { }, positionals: [] } + ], + [ + { argv: ['--foo'], opts: { optionsWithValue: 'foo' } }, + { options: {}, positionals: [] } ] ]); From b2be252ded01ebaf9723c3af923f36a514296f55 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Wed, 16 Sep 2020 15:32:05 -0700 Subject: [PATCH 12/14] add special-case for value of "false" for Flags --- doc/api/util.md | 10 ++++++---- lib/internal/util/parse_args.js | 7 ++++++- test/parallel/test-util-parseargs.js | 12 ++++++++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index 065eb80f45d27e..7a4709e88a93c1 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1043,10 +1043,12 @@ have an associated string value (e.g., `node app.js --verbose`). once) * A Flag appearing in `multiOptions` but not in the `argv` Array will be omitted from the `options` property of the returned object -* If a string value is erroneously provided in `argv` for a Flag via the `=` - separator, the string value will be replaced with `true`; e.g., - `['--require=script.js']` becomes `{options: {require: true}}, positionals: - []}` +* _Special case for negated Flags_: If a string value of `false` is provided in + `argv` for a Flag via the `=` separator, the value will become boolean + `false`, e.g., `['--verbose=false']` becomes `{options: {verbose: false}}, + positionals: []}`; any value other than the string `false` will become `true`, + and if `=` is not provided, the value is interpreted as a + [Positional][Positionals] ### Options diff --git a/lib/internal/util/parse_args.js b/lib/internal/util/parse_args.js index 76ee5799e498d9..9ccc0e470cb2c1 100644 --- a/lib/internal/util/parse_args.js +++ b/lib/internal/util/parse_args.js @@ -66,6 +66,10 @@ const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes; * // {options: {foo: [true, true]}, positionals: []} * parseArgs(['--very-wordy-option']) * // {options: {'very-wordy-option': true}, positionals: []} + * parseArgs(['--verbose=false']) + * // {options: {verbose: false}, positionals: []} + * parseArgs(['--verbose', 'false']) + * // {options: {verbose: true}, positionals: ['false']} */ const parseArgs = ( argv = ArrayPrototypeSlice(process.argv, 2), @@ -117,7 +121,8 @@ const parseArgs = ( ) || argv[++pos]; } } else { - optionValue = true; + // To get a `false` value for a Flag, use e.g., ['--flag=false'] + optionValue = optionValue !== 'false'; } if (multiOptions.has(optionName)) { diff --git a/test/parallel/test-util-parseargs.js b/test/parallel/test-util-parseargs.js index 186272e006fe81..b4f5c335536bc9 100644 --- a/test/parallel/test-util-parseargs.js +++ b/test/parallel/test-util-parseargs.js @@ -67,12 +67,20 @@ const { format, parseArgs } = require('util'); ], [ { argv: ['--foo=false'] }, + { options: { foo: false }, positionals: [] } + ], + [ + { argv: ['--foo=bar'] }, { options: { foo: true }, positionals: [] } ], [ { argv: ['--foo', 'true'] }, { options: { foo: true }, positionals: ['true'] } ], + [ + { argv: ['--foo', 'false'] }, + { options: { foo: true }, positionals: ['false'] } + ], [ { argv: ['--foo', 'true'], opts: { optionsWithValue: ['foo'] } }, { options: { foo: 'true' }, positionals: [] } @@ -86,7 +94,7 @@ const { format, parseArgs } = require('util'); ], [ { argv: ['--foo=true', '--foo=false'] }, - { options: { foo: true }, positionals: [] } + { options: { foo: false }, positionals: [] } ], [ { argv: ['--foo', 'true', '--foo', 'false'] }, @@ -109,7 +117,7 @@ const { format, parseArgs } = require('util'); ], [ { argv: ['--foo', 'true', '--foo=false'] }, - { options: { foo: true }, positionals: ['true'] } + { options: { foo: false }, positionals: ['true'] } ], [ { From 694f9c624534ddf0e32db73476964da314baa238 Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Wed, 16 Sep 2020 15:37:09 -0700 Subject: [PATCH 13/14] missing values for Options become an empty string --- doc/api/util.md | 4 ++-- lib/internal/util/parse_args.js | 2 +- test/parallel/test-util-parseargs.js | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/api/util.md b/doc/api/util.md index 7a4709e88a93c1..4460a9219b2a69 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -1062,8 +1062,8 @@ an associated value (e.g., `node app.js --require script.js`). value of `['--foo' 'bar']` is `bar` * Option values may be provided _with or without_ a `=` separator (e.g., `['--require=script.js']` is equivalent to `['--require', 'script.js']`) -* If an Option value is not provided, the Option will be omitted from the - `options` property of the returned object +* If an Option value is not found in `argv`, the associated value will be parsed + to an empty string (`''`) * An argument-like value (a value beginning with one or more dashes) immediately following an Option in the `argv` Array will cause the Option to be omitted from the `options` property of the returned object _unless_ the `=` separator diff --git a/lib/internal/util/parse_args.js b/lib/internal/util/parse_args.js index 9ccc0e470cb2c1..d1624dd36cdf65 100644 --- a/lib/internal/util/parse_args.js +++ b/lib/internal/util/parse_args.js @@ -118,7 +118,7 @@ const parseArgs = ( if (optionValue === undefined) { optionValue = ( argv[pos + 1] && StringPrototypeStartsWith(argv[pos + 1], '-') - ) || argv[++pos]; + ) || argv[++pos] || ''; } } else { // To get a `false` value for a Flag, use e.g., ['--flag=false'] diff --git a/test/parallel/test-util-parseargs.js b/test/parallel/test-util-parseargs.js index b4f5c335536bc9..8edcb559174bcb 100644 --- a/test/parallel/test-util-parseargs.js +++ b/test/parallel/test-util-parseargs.js @@ -156,7 +156,7 @@ const { format, parseArgs } = require('util'); ], [ { argv: ['--foo'], opts: { optionsWithValue: 'foo' } }, - { options: {}, positionals: [] } + { options: { foo: '' }, positionals: [] } ] ]); From 3a7f3b1bbf913e9e3117a8523d6ba00aca042bff Mon Sep 17 00:00:00 2001 From: Christopher Hiller Date: Thu, 17 Sep 2020 11:31:32 -0700 Subject: [PATCH 14/14] update signature in util.md --- doc/api/util.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/util.md b/doc/api/util.md index 4460a9219b2a69..37b7b9e1053874 100644 --- a/doc/api/util.md +++ b/doc/api/util.md @@ -951,7 +951,7 @@ equality. added: REPLACEME --> -* `argv` {string[]|Object} (Optional) Array of argument strings; defaults +* `argv` {string[]} (Optional) Array of argument strings; defaults to [`process.argv.slice(2)`](process_argv). If an Object, the default is used, and this parameter is considered to be the `options` parameter. * `options` {Object} (Optional) The `options` parameter is an