profile
viewpoint
Christopher Hiller boneskull @IBM Ridgefield, WA, USA https://boneskull.com advertisement

boneskull/angular-tags 135

Pure AngularJS tagging widget with typeahead support courtesy of ui-bootstrap

bebraw/grunt-umd 94

Surrounds code with the universal module definition (MIT)

boneskull/angularjs-edge 12

Examples for the book Developing an AngularJS Edge by Christopher Hiller

bebraw/libumd 9

Wraps given JavaScript code with UMD (MIT)

boneskull/angular-autoselect 6

AngularJS directive(s) to automatically select text within input fields

boneskull/all-types 4

All DefinitelyTyped typedefs, installed globally, for WebStorm & other JetBrains IDEs

boneskull/alfred-npms 3

Alfred 3 workflow for npms.io

boneskull/angular-mocks-node 2

AngularJS' ngMock module provided as a CommonJS module.

boneskull/angular-history 1

A history service for AngularJS. Undo/redo, that sort of thing. Has nothing to do with the "back" button, unless you want it to.

PR closed nodejs/node

util: add util.parseArgs() build notable-change semver-minor tsc-agenda util

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

<!-- Thank you for your pull request. Please provide a description above and review the requirements below.

Bug fixes and new features should include tests and possibly benchmarks.

Contributors guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md -->

Checklist

<!-- Remove items that do not apply. For completed items, change [ ] to [x]. -->

  • [x] make -j4 test (UNIX), or vcbuild test (Windows) passes
  • [x] tests and/or benchmarks are included
  • [x] documentation is changed or added
  • [x] commit message follows commit guidelines

<!-- Developer's Certificate of Origin 1.1

By making a contribution to this project, I certify that:

(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or

(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or

(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.

(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved. -->


Motivation

While this has been discussed at length in the Node.js Tooling Group and its associated issue, let me provide a summary:

  • process.argv.slice(2) is rather awkward boilerplate, especially for those new to Node.js
  • Parsing options without the use of a userland module reliably requires, well, about as much code as this PR adds; the complexity quickly ramps up going from one argument to two
  • It's often useful to add a few command-line flags in an ad-hoc manner to, say, app.js
  • It's often useful to parse command-line flags in example code, which would otherwise demand installation of a userland module (thus complicating things)

process.parseArgs() makes handling command-line arguments "natively" much easier. Given that so many tools are being written in Node.js, it makes sense to center this experience.

Design Considerations

First, let me acknowledge that there are many ways to parse command-line arguments. There is no standard, cross-platform, agreed-upon convention. Command-line arguments look different in Windows vs. POSIX vs. GNU, and there's much variation across programs. And these are still conventions, not hard & fast requirements. We can easily be paralyzed attempting to choose what "styles" to support or not. It is certain that there will be someone who agrees that Node.js should have this feature, but should not do it in this way.

But to implement the feature, we have to do it in some way. This is why the way is the way it is:

I have researched the various features and behavior of many popular userland command-line parsing libraries, and have distilled it down to the most commonly supported features, while striving further to trim any features which are not strictly necessary to get the bulk of the work done. While these do not align to, say, POSIX conventions, they do align with end-user expectations of how a Node.js CLI should work. What follows is consideration of a few specific features.

The Requirement of = for Options Expecting a Value

For example, one may argue that --foo=bar should be the only way to use the value bar for the option foo; but users of CLI apps built on Node.js expect --foo bar to work just as well. There was not a single popular argument-parsing library that did not support this behavior. Thus, process.parseArgs() supports this behavior (it cannot be automatic without introducing ambiguity, but I will discuss that later).

Combination of Single-Character Flags

Another one is combining (or concatenating?) "short flags"--those using a single hyphen, like -v--where -vD would be equivalent to -v -D. While this is a POSIX convention, it is not universally supported by the popular command-line parsers. Since it is inherently sugar (and makes the implementation more complicated), we chose not to implement it.

Data Types

Like HTML attribute values (<tag attr="1">), command-line arguments are provided to programs as strings, regardless of the data type they imply. While most of the userland arg parsers support some notion of a "data type"-i.e., this argument value is a number, string, or boolean--it is not strictly necessary. It is up to the user to handle the coercion of these values.

Default Behavior: Boolean Flags

The default behavior is to treat anything that looks like an argument (that's mainly "arguments beginning with one or more dashes") as a boolean flag. The presence of one of these arguments implies true. From investigation of popular CLI apps, we found that most arguments are treated as boolean flags, so it makes sense for this to be the default behavior. This means that a developer who just wants to know whether something is "on" or "off" will not need to provide any options to process.parseArgs().

Handling Values

Some arguments do need values, (e.g., --require my-script.js), and in order to eliminate ambiguity, the API consumer must define which arguments expect a value. This is done via the expectsValue option to process.parseArgs(), which is the only option to process.parseArgs(). This is the only option process.parseArgs() accepts.

Possible alternatives:

  • Rename expectsValue to something else

Repeated Arguments

It's common to need to support multiple values for a single argument, e.g., --require a.js --require b.js. In this example, require needs to be listed in the expectsValue option. The result is an object containing a require property whose value is an array of strings; ['b.js', 'c.js']. In the example of --require c.js, the value of the require property is a string, 'c.js'.

When working with boolean flags (those not declared in expectsValue), it was trivial to support the case in which repeated arguments result in a count. One -v will result in an object where {v: true}, but -v -v will result in {v: 2}. Either way, the value will be truthy.

Possible alternatives:

  • Every argument expecting a value (as declared in expectsValue) will parse to Array of strings, even if there is only one string in the Array (e.g., --require c.js becomes {require: ['c.js']}. That makes the API more consistent at the expense of making the common case (no repetition) slightly more awkward.
  • Remove the "count" behavior. While this is widely supported by modules, I don't often see it used in the wild in Node.js CLI apps.

Positional Arguments

Arguments after -- or without a dash prefix are considered "positional". These are placed into the Array property _ of the returned object. This is a convention used by many other userland argparsers in Node.js. It is always present, even if empty. This also means that _ is reserved as a flag/option name (e.g., --_ will be ignored).

Possible alternatives:

  • Throw if _ is provided in expectsValue

Intended Audience

It is already possible to build great arg parsing modules on top of what Node.js provides; the prickly API is abstracted away by these modules. Thus, process.parseArgs() is not necessarily intended for library authors; it is intended for developers of simple CLI tools, ad-hoc scripts, deployed Node.js applications, and learning materials.

It is exceedingly difficult to provide an API which would both be friendly to these Node.js users while being extensible enough for libraries to build upon. We chose to prioritize these use cases because these are currently not well-served by Node.js' API.

Questions

  • In particular, I'm not 100% confident in the terminology I chose for the documentation ("Flags", "Options", "Positionals"). This does align with other documentation I've read on the subject of CLI arguments, I am unsure if introducing this terminology to our documentation is a Good Idea. Perhaps it can be expressed without new terminology.

  • I sorted some files around my modification in in node.gyp, which looked like it wanted to be in order, but was not. It did not seem to affect the build, but I can revert these changes if need be.

  • Should it be process.parseArgv()? While it does parse process.argv by default, it does not necessarily need to be used with process.argv.

  • Do I need to do more input validation, throw more exceptions, or take other defensive measures?

Credits

While this is my implementation, the design is a product of work by myself, @bcoe, @ruyadorno, and @nodejs/tooling.

+518 -0

88 comments

6 changed files

boneskull

pr closed time in 5 days

pull request commentnodejs/node

util: add util.parseArgs()

@mmarchini I think that is reasonable.

boneskull

comment created time in 6 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+added: REPLACEME+-->++* `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+  object supporting the following properties:+  * `optionsWithValue` {string[]|string} (Optional) One or more argument+    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][]+  * `positionals` {string[]}, 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();++if (argv.foo === true) {

yes

boneskull

comment created time in 6 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

I don't believe balancing these concerns is impossible.

OKAY, what about this:

We want to know if an end-user gave us weird or unexpected input. A flag having a value, for instance. e.g., --verbose=yes is unexpected; --verbose was the correct usage.

Instead of just returning {options: {verbose: 'yes'}}, we return {options: {}, errors: [SomeError]}, where errors is one or more Problems.

This way, we can:

  1. keep the value of "flags" as boolean true (consistent types) and
  2. we lose no information and
  3. we do not throw.

This means that --verbose=false is an "error." The developer can choose how to interpret what was provided. SomeError could be an actual exception or not, but a code and contextual information would be helpful, so I'm leaning towards yes.

Likewise, if optionsWithValues was specified, a missing value would also be considered an "error", instead of returning an empty string.

boneskull

comment created time in 6 days

pull request commentnodejs/node

util: add util.parseArgs()

Won't be pushing any changes until Tuesday. I plan on implementing this and updating the documentation accordingly.

boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

@mmarchini I haven't rebased... what are you referring to?

boneskull

comment created time in 7 days

issue commentnodejs/tooling

Node.js Tooling Group Meeting 2020-09-18

this is the deep dive FS meeting since it didn't happen last time

here are the notes

https://hackmd.io/@nodejs-tooling/BkCIZ9fHv

mhdawson

comment created time in 7 days

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function removeAsync(dir) {   dir = nextDirPath();   makeNonEmptyDirectory(1, 10, 2, dir, true);   removeAsync(dir);++  // Should fail if target does not exist+  fs.rmdir(+    path.join(tmpdir.path, 'noexist.txt'),+    { recursive: true },+    common.mustCall((err) => {+      assert.strictEqual(err.code, 'ENOENT');+    })+  );++  // Should fail if target is a file+  const filePath = path.join(tmpdir.path, 'rmdir-async-file.txt');+  fs.writeFileSync(filePath, '');+  fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {+    assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');+    assert.strictEqual(err.name, 'TypeError');+    assert.match(err.message, /^The argument 'path' is not a directory\./);+    fs.unlinkSync(filePath);

this needs a try/finally as well because these assert calls may throw

iansu

comment created time in 7 days

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function rimrafPromises(path, options) { function rimrafSync(path, options) {   let stats; +  try {+    stats = statSync(path);+  } catch (err) {+    if (err.code === 'ENOENT')

it looks like you'd get into trouble here if L198 threw, because stats would then be undefined, and the call to isDirectory() on L204 would fail... it doesn't seem recoverable?

iansu

comment created time in 7 days

PullRequestReviewEvent
PullRequestReviewEvent

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function rimrafPromises(path, options) { function rimrafSync(path, options) {   let stats; +  try {+    stats = statSync(path);+  } catch (err) {+    if (err.code === 'ENOENT')+      throw err;+  }++  if (!stats.isDirectory()) {+    throw new ERR_INVALID_ARG_VALUE('path', path, 'is not a directory');

There doesn't seem to be a convenience function for this error; maybe we should create one.

iansu

comment created time in 7 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

It's important that @tniessen gives the green light to this strategy.

boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

@gabrielschulhof So essentially you're proposing:

  • if you do not use optionsWithValues, you can expect a boolean true, string, or undefined
  • if you use optionsWithValues, you can expect a string (empty string in the case of a missing value) or undefined
boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

So IMO needs to be boolean true or false as originally designed. Maybe we just turn any value into false if no value is expected, so we don't need a list of values to recognize.

Reminder: perfect is the enemy of good

boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

This exactly what it did before I changed it to recognize =false. Are you saying to rip that coercion out, and instead just return a string value (instead of the default boolean true) if = is used?

TBH I don't love this either, because if you are expecting a boolean and get a nonempty string...

let argv = parseArgs(['--enable-goodtimes-virus=NO'])

if (argv['enable-goodtimes-virus']) {
  // leave nasty voicemail 
}
boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

I mentioned that above, I think.

boneskull

comment created time in 7 days

pull request commentmochajs/mocha

do not leak polyfills into global context; closes #4423

I think I could curate the polyfills w/o needing to swap out babel. it just seems incredibly weird that babel won't handle this for us.

afaict there are some movements in this direction (babel-polyfill-corejs3 for instance) but I haven't been able to get it working. seems experimental at this point, but I think that's the problem trying to be solved.

configuring babel is so much not fun. it is very low-level, and I think our use-case is unique enough to make something higher-level out of reach as wel

boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

Can we please decide what we will approve? I am not interested in making another change and then needing to do another round of changes. The recent concerns should have been raised much more explicitly earlier in the process.

The next change I make here should be the final one. If someone is unhappy with how, say, --foo bar works, please describe how it should work instead of waiting for me to make a change as @tniessen is suggesting, then coming up with something else.

Note: I am uninterested in throwing exceptions based on the content of argv and am also uninterested in addressing @devsnek's initial concern. I would also like to know if the @nodejs/tsc would request either of these changes, so I can close this PR. I do not want to do more work here for the PR to be blocked for these reasons. Hopefully someone from the TSC can answer this.

I will wait until next week for further feedback before updating the PR.

boneskull

comment created time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

@tniessen I agree with your point, but it means that the types returned by the API will be either strings or boolean and we cannot say for sure which the developer will receive. This is what I was trying to avoid, since there were concerns about types elsewhere. Which concern is more important?

boneskull

comment created time in 7 days

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function rimrafPromises(path, options) { function rimrafSync(path, options) {   let stats; +  try {+    stats = statSync(path);+  } catch (err) {+    if (err.code === 'ENOENT')+      throw err;+  }++  if (!stats.isDirectory()) {+    throw new ERR_INVALID_ARG_VALUE('path', path, 'is not a directory');

is this the correct error to throw? unsure of the intent of ERR_INVALID_ARG_VALUE

iansu

comment created time in 7 days

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function removeAsync(dir) {   dir = nextDirPath();   makeNonEmptyDirectory(1, 10, 2, dir, true);   removeAsync(dir);++  // Should fail if target does not exist+  fs.rmdir(+    path.join(tmpdir.path, 'noexist.txt'),+    { recursive: true },+    common.mustCall((err) => {+      assert.strictEqual(err.code, 'ENOENT');+    })+  );++  // Should fail if target is a file+  const filePath = path.join(tmpdir.path, 'rmdir-async-file.txt');+  fs.writeFileSync(filePath, '');+  fs.rmdir(filePath, { recursive: true }, common.mustCall((err) => {+    assert.strictEqual(err.code, 'ERR_INVALID_ARG_VALUE');+    assert.strictEqual(err.name, 'TypeError');+    assert.match(err.message, /^The argument 'path' is not a directory\./);+  }));+  fs.unlinkSync(filePath);

imo this should be guaranteed to be called--not sure if it is. also: don't know offhand if other tests try to guarantee this or just leave crap all over the fs

iansu

comment created time in 7 days

Pull request review commentnodejs/node

Make recursive rmdir more strict

 function rimrafPromises(path, options) { function rimrafSync(path, options) {   let stats; +  try {+    stats = statSync(path);+  } catch (err) {+    if (err.code === 'ENOENT')

what is swallowed here if not ENOENT?

iansu

comment created time in 7 days

PullRequestReviewEvent
PullRequestReviewEvent

push eventmochajs/mocha

Christopher Hiller

commit sha e2b5d9975e19ec59391c48583f59343980044717

fix lintstagedrc maybe Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

view details

Christopher Hiller

commit sha c190c40be88989ab86abdb68e95c34cbf6ca9394

try different strategy Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

view details

push time in 7 days

issue commentyargs/yargs

Webpack building broken

fwiw ncc may be more suitable for this use-case. or even rollup. I can't imagine the node target is really first-class in webpack, and I am not surprised that it doesn't work well with Node.js' spec-compliant implementation

dl748

comment created time in 7 days

push eventmochajs/mocha

Christopher Hiller

commit sha ad001b8138c837cb1e36e21c4e61936fac120837

different magic configuration

view details

push time in 7 days

pull request commentnodejs/node

util: add util.parseArgs()

@mhdawson Looks like it's ready for @nodejs/tsc vote unless more reviewers come along...

boneskull

comment created time in 8 days

push eventmochajs/mocha

Christopher Hiller

commit sha 155d10bd55c5d7634aca2689d0fcfd3f9ed19ee1

add missing target to rollup config Signed-off-by: Christopher Hiller <boneskull@boneskull.com>

view details

push time in 8 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+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 is an

I don't think there's any clear & obvious change to be made here. if someone thinks of one, a future PR can address it, but IMO this is good enough for now

boneskull

comment created time in 8 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

@mcollina Updated the doc signature as you noted (somewhere... thanks github)

boneskull

comment created time in 8 days

push eventboneskull/node

Christopher Hiller

commit sha 3a7f3b1bbf913e9e3117a8523d6ba00aca042bff

update signature in util.md

view details

push time in 8 days

pull request commentnodejs/node

fs: remove experimental language from rmdir recursive

after discussion w/ @bcoe I also agree on his strategy here

bcoe

comment created time in 8 days

pull request commentnodejs/node

util: add util.parseArgs()

I have made two changes as requested:

  1. A flag of --foo=false is now a special case where the value in the parsed object becomes boolean false. This is the only way to get a boolean false. Example:

    parseArgs(['--verbose=false']) // {options: {verbose: false}, positionals: []}
    

    @gabrielschulhof, @tniessen, others

  2. A "missing" value where one was expected (via an Option defined using optionsWithValues) is no longer omitted from the parsed object, but rather it parses to an empty string:

    parseArgs(['--foo'], {optionsWithValues: 'foo'}) // {options: {foo: ''}, positionals: []}
    

    @bcoe

also @mcollina please re-review, as I think what you were requesting changes on was outdated.

boneskull

comment created time in 8 days

push eventboneskull/node

Christopher Hiller

commit sha 694f9c624534ddf0e32db73476964da314baa238

missing values for Options become an empty string

view details

push time in 8 days

push eventboneskull/node

Christopher Hiller

commit sha b2be252ded01ebaf9723c3af923f36a514296f55

add special-case for value of "false" for Flags

view details

push time in 8 days

pull request commentnodejs/node

util: add util.parseArgs()

OK, I am going to add a special case for the following situation:

  • arg is a flag
  • in the input, an arg (--foo) is immediately followed by =false

this will be the only way to get a value of boolean false out of this API. this will be case-sensitive

boneskull

comment created time in 9 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+added: REPLACEME+-->++* `argv` {string[]|Object} (Optional) Array of argument strings; defaults

btw this comment is in regards to a docstring, unless you are talking about something else

boneskull

comment created time in 9 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

What exactly is the requested behavior, then? Is this a special case for the string "false"? Does this only apply when using =? Does it convert to a boolean the arg is present in optionsWithValues, or only when it is not? Does it not convert to boolean, and instead returns a string--so the possible values are boolean true and string false? And then the opposite when optionsWithValues is used?

It may seem unintuitive at first glance, but the requested behavior both adds complexity to the implementation and makes even describing the behavior more difficult to understand.

boneskull

comment created time in 9 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+added: REPLACEME+-->++* `argv` {string[]|Object} (Optional) Array of argument strings; defaults

@mcollina It allows someone to supply an explicit array of arguments, or just an options object, where the value would default to process.argv. we could make it so you must pass process.argv, but that is likely boilerplate in 90% of cases.

boneskull

comment created time in 9 days

PullRequestReviewEvent

pull request commentnodejs/node

fs: remove experimental language from rmdir recursive

It should not remove a file if given a file (unsure if that's still a bug). But it should remove all files within a directory if given a directory.

bcoe

comment created time in 10 days

pull request commentmochajs/mocha

do not leak polyfills into global context; closes #4423

yeah, I am not sure how to do this. using the "runtime" babel helper, doesn't make sense, because everything must be bundled (no externals). using "bundled" pollutes the globals.

boneskull

comment created time in 10 days

pull request commentmochajs/mocha

do not leak polyfills into global context; closes #4423

still misconfigured... i hate javascript

boneskull

comment created time in 10 days

PR opened mochajs/mocha

do not leak polyfills into global context; closes #4423 confirmed-bug semver-patch

when we transitioned to Rollup/Babel, we misconfigured Babel such that all language APIs polyfilled by core-js would be accessible not just by Mocha, but by tests and code under test.

This change attempts to "restrict" the polyfills to Mocha itself.

I'm not entirely sure the best way to test this, since our tests also get bundled and would thus have access to our polyfills. We need to basically add a separate script to a Karma config which would get loaded via <script> tag to make any assertions about the global environment. I am too lazy to do this rn.

Will it work with IE? Let's find out.

Bonus: 50k bundle size reduction!

+49 -16

0 comment

3 changed files

pr created time in 10 days

create barnchmochajs/mocha

branch : boneskull/issue/4423-polyfill-leak

created branch time in 10 days

issue commentmochajs/mocha

Mocha 8.1.0 adds forEach property to CSSStyleDeclaration, at least inside a Proxy

This is symptomatic of a bigger issue: we are leaking polyfills into the global context.

I think I might have a fix for this... sending PR

edwinm

comment created time in 10 days

issue commentmochajs/mocha

Mocha 8.1.0 adds forEach property to CSSStyleDeclaration, at least inside a Proxy

This is surfacing via core-js and may be configurable via babel options. See https://github.com/zloirock/core-js/pull/249

I'll take a further look.

edwinm

comment created time in 10 days

issue closedmochajs/mocha

Cleanup and management of command line arguments

Is your feature request related to a problem or a nice-to-have?? Please describe.

When a program access the process.argv array to get the command line, it just crashes since the command line is dirty due to the running of mocha, i.e.:

  • there will be mocha as first parameter
  • possibly, there will follow the mocha parameters
  • there will be no way to pass program/test specific arguments (i.e. arguments not managed by mocha)

For example:

mocha --require source-map-support/register --timeout 5000 "dist/tests/**/*_spec.js" --my-option

Describe the solution you'd like A solution could be the following:

  • mocha will automatically always clean up the process.argv array
  • as first parameter of the new process.argv, mocha could place the name of the current _spec file running
  • if in the command line there is a double-dash "--", the remaining parameters are not parsed by mocha but assumed as test/program parameters, and therefore added to the new process.argv

For example, the following command line:

mocha --require source-map-support/register --timeout 5000 "dist/tests/**/*_spec.js" -- --my-option

could be transformed by mocha as:

dist/tests/mytest_spec.js --my-option

Describe alternatives you've considered

I searched internet without success.

closed time in 10 days

FStefanni

issue commentmochajs/mocha

Cleanup and management of command line arguments

Hi,

Since your program is expecting process.argv to have a certain value, to test your program, you can:

  1. Use child_process.spawn() or other to create a subprocess with the particular args (if you want an integration/functional test), or
  2. Use a hook or root hook (see https://mochajs.org/#root-hook-plugins) to fiddle with process.argv yourself
FStefanni

comment created time in 10 days

issue closedmochajs/mocha

Support Yarn Workspaces/Monorepos with `--require`

Is your feature request related to a problem or a nice-to-have?? Please describe. --require can't find some modules, like ts-node/register, when working in a yarn workspace.

Describe the solution you'd like I'd like to see --require find modules when using yarn workspaces.

Describe alternatives you've considered Jest doesn't support the exports style of "ui" or I might use Jest.

Right now I do this: mocha --require ./mocha-ts-node-compat.js

./mocha-ts-node-compat.js contents:

require('ts-node/register');

Additional context In all honesty, this could be a problem with ts-node, I noticed that it doesn't seem to be "hoisted" by yarn, but I don't know enough about the reasons behind that to say one way or the other just yet.

closed time in 10 days

resistdesign

issue commentmochajs/mocha

Support Yarn Workspaces/Monorepos with `--require`

This is not a mocha problem and is likely due to misuse/misconfiguration of workspaces

(you can also use mocha --require ts-node/register but that's not likely to work if your file above doesn't)

Ensure you are running mocha from a directory that has a node_modules containing ts-node. You can also likely get some magic path resolution by adding mocha to your test lifecycle script in package.json. But I don't know enough about how yarn handles workspaces to help further

resistdesign

comment created time in 10 days

issue commentmochajs/mocha

Mocha does not pass "--prof" parameter to Node and thus does not allow for profiling

For anyone who wants to use --prof:

  1. All V8 options (of which --prof is one) can be specified by prepending --v8- to the flag name, so use --v8-prof
  2. Alternatively, use NODE_OPTIONS=--prof env var
FlourishS

comment created time in 10 days

issue closedmochajs/mocha

Mocha does not pass "--prof" parameter to Node and thus does not allow for profiling

Expected

When mocha is run with the --prof argument it will pass this argument to Node thus enabling Node to be profiled.

Example package.json:

...
  "scripts": {
    "start": "nodemon ./bin/www",
    "test": "mocha --prof --exit",
...

Actual

The --prof argument is not passed to Node. It is therefore not possible to run node in profiling mode when using Mocha.

A dirty workaround is to patch bin/mocha as follows:

// sort options into "node" and "mocha" buckets
Object.keys(opts).forEach(opt => {
  if (isNodeFlag(opt) || opt == 'prof') { // dirty workaround
    console.log("node flag: " + opt);
    nodeArgs[trimV8Option(opt)] = opts[opt];
  } else {
    console.log("mocha flag: " + opt);
    mochaArgs[opt] = opts[opt];
  }
});

Tested with Mocha 8.1.2 and Node v12.15.0

Thank you very much for considering this bug.

closed time in 10 days

FlourishS

PR closed mochajs/mocha

Add support for node v8 option 'prof' parameter (#4433) confirmed-bug node.js

Requirements

  • Filling out the template is required. Any pull request that does not include enough information to be reviewed in a timely manner may be closed at the maintainers' discretion.
  • All new code requires tests to ensure against regressions.

Description of the Change

<!--

We must be able to understand the design of your change from this description. Keep in mind that the maintainers and/or community members reviewing this PR may not be familiar with the subsystem. Please be verbose.

-->

I modified --prof to be considered as a 'Node' flag so that Node can handle it.

Alternate Designs

<!-- Explain what other alternates were considered and why the proposed version was selected -->

N/A

Why should this be in core?

<!-- Explain why this functionality should be in mocha as opposed to its own package -->

#4433

Benefits

<!-- What benefits will be realized by the code change? -->

Users can pass --prof argument to mocha and Node can handle it by profiling.

Possible Drawbacks

<!-- What are the possible side-effects or negative impacts of the code change? -->

N/A

Applicable issues

<!--

  • Enter any applicable Issues here.

  • Mocha follows semantic versioning: http://semver.org

  • Is this a breaking change (major release)?

  • Is it an enhancement (minor release)?

  • Is it a bug fix, or does it not impact production code (patch release)? -->

#4433

+6 -1

5 comments

2 changed files

Donghoon759

pr closed time in 10 days

pull request commentmochajs/mocha

Add support for node v8 option 'prof' parameter (#4433)

Either way, sounds like we have some agreement that we don't want to merge this.

The reasoning is:

  1. There are multiple workarounds; --v8-prof and NODE_OPTIONS=--prof
  2. The regex is "historical" and should not be updated (I didn't check to see if this is actually in the code comments there, but it should be).

Thank you!

Donghoon759

comment created time in 10 days

pull request commentmochajs/mocha

Add support for node v8 option 'prof' parameter (#4433)

@juergba it's because --prof is not a Node option per se--it's a V8 option. Node supports a subset of these "natively", and a subset of those in NODE_OPTIONS.

Further, NODE_OPTIONS and the allowed command-line flags are not 1:1. For example, --preserve-symlinks is a command-line option for node, but it is not allowed in NODE_OPTIONS.

For this reason, I don't think we can just do away with it entirely and demand users use NODE_OPTIONS.

Donghoon759

comment created time in 10 days

pull request commentmochajs/mocha

Support multipart extensions like ".test.js"

(relying on the presence of a certain shell or configuration thereof for glob parsing is--as you have found out--fraught with peril)

jordanstephens

comment created time in 10 days

pull request commentmochajs/mocha

Support multipart extensions like ".test.js"

Ah... well, you can quote your globs--which will be handled by the glob module--and you won't have to worry about the shell (or even if it runs on Windows).

mocha 'src/foo/**/*.test.js'

should work fine either way. likewise you can throw this into your .mocharc.json:

{ "spec": "blah/**/*.test.js" }
jordanstephens

comment created time in 10 days

pull request commentnodejs/node

util: add util.parseArgs()

  • I've corrected the issue the fuzzer complained about, thanks @tniessen (how did you do that?)
  • Various documentation/docstring fixes
  • Changed while loop
boneskull

comment created time in 11 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+added: REPLACEME+-->++* `argv` {string[]|Object} (Optional) Array of argument strings; defaults

would prefer to leave as-is unless the convention is explicitly documented somewhere. afaik doing it the suggested way does not work very well if your docstrings are read by machines (e.g., TS language server), which is why I wrote it the way I did

boneskull

comment created time in 11 days

PullRequestReviewEvent

push eventboneskull/node

Christopher Hiller

commit sha 97f7e88a68cd487ac9b95c811ceec7c0dd8cb0a2

review updates

view details

push time in 11 days

pull request commentnodejs/node

util: add util.parseArgs()

Flags do not have "values" per the definition here; a Flag, if present in argv, is true. A developer must choose whether or not to expect a "value". If a developer wants to, say, have a default value of true for --something and allow a user to specify --something=false, a developer could use {optionsWithValue: 'something'} and look for the string 'false'.

argv.something = argv.something !== 'false' ;
boneskull

comment created time in 11 days

pull request commentnodejs/node

util: add util.parseArgs()

why would --something=false not make sense? The concept of a "default value" is something in the program using this API - iow, this API can't reliably assume a default value of "false" for an absent parameter, just like it can't reliably assume a default value of "true".

I don't understand; maybe I was not clear. When I say "roughly equivalent to" I mean the absence of a flag which was not specified in argv is falsy by nature of being undefined.

boneskull

comment created time in 11 days

Pull request review commentnodejs/node

util: add util.parseArgs()

+'use strict';++const {+  ArrayIsArray,+  ArrayPrototypePush,+  ArrayPrototypeSlice,+  SafeSet,+  StringPrototypeReplace,+  StringPrototypeSplit,+  StringPrototypeStartsWith,+} = primordials;+const { ERR_INVALID_ARG_TYPE } = require('internal/errors').codes;++/**+ * Returns an Object representation of command-line arguments.+ *+ * Default behavior:+ * - All arguments are considered "boolean flags"; in the `options` property of+ *   returned object, the key is the argument (if present), and the value will+ *   be `true`.+ * - Uses `process.argv.slice(2)`, but can accept an explicit array of strings.+ * - 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 (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+ * strings+ * @param {Object} [options] - Options+ * @param {string[]|string} [opts.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+ * @returns {{options: Object, positionals: string[]}} Parsed arguments+ * @example+ * parseArgs(['--foo', '--bar'])+ *   // {options: { foo: true, bar: true }, positionals: []}+ * parseArgs(['--foo', '-b'])+ *   // {options: { foo: true, b: true }, positionals: []}+ * parseArgs(['---foo'])+ *   // {options: { foo: true }, positionals: []}+ * parseArgs(['--foo=bar'])+ *   // {options: { foo: true }, positionals: []}+ * parseArgs([--foo', 'bar'])+ *   // {options: {foo: true}, positionals: ['bar']}+ * parseArgs(['--foo', 'bar'], {optionsWithValue: 'foo'})+ *   // {options: {foo: 'bar'}, positionals: []}+ * parseArgs(['foo'])+ *   // {options: {}, positionals: ['foo']}+ * parseArgs(['--foo', '--', '--bar'])+ *   // {options: {foo: true}, positionals: ['--bar']}+ * parseArgs(['--foo=bar', '--foo=baz'])+ *   // {options: {foo: true}, positionals: []}+ * parseArgs(['--foo=bar', '--foo=baz'], {optionsWithValue: 'foo'})+ *   // {options: {foo: 'baz'}, positionals: []}+ * parseArgs(['--foo=bar', '--foo=baz'], {+ *   optionsWithValue: 'foo', multiOptions: 'foo'+ * }) // {options: {foo: ['bar', 'baz']}, positionals: []}+ * parseArgs(['--foo', '--foo'])+ *   // {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),+  options = { optionsWithValue: [] }+) => {+  if (!ArrayIsArray(argv)) {+    options = argv;+    argv = ArrayPrototypeSlice(process.argv, 2);+  }+  if (typeof options !== 'object' || options === null) {+    throw new ERR_INVALID_ARG_TYPE(+      'options',+      'object',+      options);+  }+  if (typeof options.optionsWithValue === 'string') {+    options.optionsWithValue = [options.optionsWithValue];+  }+  if (typeof options.multiOptions === 'string') {+    options.multiOptions = [options.multiOptions];+  }+  const optionsWithValue = new SafeSet(options.optionsWithValue || []);+  const multiOptions = new SafeSet(options.multiOptions || []);+  const result = { positionals: [], options: {} };++  let pos = 0;+  while (true) {+    const arg = argv[pos];+    if (arg === undefined) {

This is moot due to changing the while loop

boneskull

comment created time in 11 days

PullRequestReviewEvent

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+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 is an

Certainly we say "option" a lot, but I am unsure how to reconcile this given the word "option" is used in both JS and CLI contexts to mean entirely separate things. Even if we adopted the IEEE standard terminology, we'd still have that problem.

boneskull

comment created time in 11 days

PullRequestReviewEvent

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+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 is an+  object supporting the following properties:+  * `optionsWithValue` {string[]|string} (Optional) One or more argument+    strings which _expect a value_ when present in `argv` (see [Options][]+    for details)+  * `multiOptions` {string[]|string} (Optional) One or more argument

I see. Maybe changing this name to multiple would make more sense?

boneskull

comment created time in 11 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

--something=false doesn't make a lot of sense, because there is--intentionally--no concept here of "default values". Omitting --something, is in fact (roughly equivalent to), --something=false. A developer could look for the --no-something flag, if necessary, but --something=<value> (when not expecting a value) is a misuse of the interface by the end-user.

boneskull

comment created time in 11 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+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 is an+  object supporting the following properties:+  * `optionsWithValue` {string[]|string} (Optional) One or more argument+    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][]+  * `positionals` {string[]}, 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();++if (argv.foo === true) {+  console.log(argv.positionals); // prints [ 'bar', 'baz' ]+}+```++Example using a custom `argv` and the `optionsWithValue` option:++```js+const argv = util.parseArgs(+  ['--foo', 'bar', 'baz'],+  { optionsWithValue: ['foo'] }+);++// argv.foo === 'bar'+if (argv.foo === 'bar') {+  console.log(argv.positionals); // prints [ 'baz' ]+}+```++Example using custom `argv`, `optionsWithValue`, and the `multiOptions` option:++```js+const argv = util.parseArgs(+  ['--foo', 'bar', '--foo', 'baz'],+  { optionsWithValue: 'foo', multiOptions: 'foo' }+);++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++_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

No, flags are generally more common.

boneskull

comment created time in 11 days

PullRequestReviewEvent

Pull request review commentnodejs/node

util: add util.parseArgs()

 Otherwise, returns `false`. See [`assert.deepStrictEqual()`][] for more information about deep strict equality. +## `util.parseArgs([argv][, options])`+<!-- YAML+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 is an+  object supporting the following properties:+  * `optionsWithValue` {string[]|string} (Optional) One or more argument+    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][]+  * `positionals` {string[]}, 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();++if (argv.foo === true) {+  console.log(argv.positionals); // prints [ 'bar', 'baz' ]+}+```++Example using a custom `argv` and the `optionsWithValue` option:++```js+const argv = util.parseArgs(+  ['--foo', 'bar', 'baz'],+  { optionsWithValue: ['foo'] }+);++// argv.foo === 'bar'+if (argv.foo === 'bar') {+  console.log(argv.positionals); // prints [ 'baz' ]+}+```++Example using custom `argv`, `optionsWithValue`, and the `multiOptions` option:++```js+const argv = util.parseArgs(+  ['--foo', 'bar', '--foo', 'baz'],+  { optionsWithValue: 'foo', multiOptions: 'foo' }+);++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++_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+* 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:+  []}`

correct

boneskull

comment created time in 11 days

PullRequestReviewEvent

pull request commentnodejs/node

fs: remove experimental language from rmdir recursive

  • To be clear: I am -1 on deprecating any part of the recursive flag in any manner
  • The current behavior is useful and what most consumers want.
  • While it works for most, the recursive flag does not work for all, as noted
  • Removing the "experimental" status is not mutually exclusive with adding an option for changing ENOENT behavior
bcoe

comment created time in 11 days

PullRequestReviewEvent

issue commentnodejs/package-maintenance

Suggest ignoring a vulnerability by the package maintainer

It does not affect my opinion until it lands for JS, is open source (we need everybody using naive security checks to use something smarter, and they are not all Snyk users), and works as advertised.

naugtur

comment created time in 13 days

pull request commentmochajs/mocha

Support multipart extensions like ".test.js"

Thanks for the PR. To be clear: is using globs a workaround for this?

jordanstephens

comment created time in 14 days

push eventmochajs/mocha

Park Juhyung

commit sha 5bdc20815b5a896ee4bc666f688dfc2404b84d42

remove unused interface tests (#4247) * Remove bdd.spec.js and tdd.spec.js These tests are deprecated. Only a few tests in the last of the files that checks clear cases were running. Since there are integration tests that checks the `only` behavior in integration/only.spec.js, it's okay to remove these tests. * Remove qunit.spec.js qunit.spec.js was not exeuced in `npm run test`. Also there are integration tests for the qunit in integration/only.spec.js. * Remove unused bdd.spec.js and tdd.spec.js

view details

push time in 14 days

PR merged mochajs/mocha

Fix the usage of expect(a, 'to be', b) qa semver-patch

The current unexpected library does not support expect(a, 'to be', b, 'some other text') format. Since these expect calls are not executed in 'npm run test', it was not found before.

Description of the Change

You can test the expect function in this repl: https://runkit.com/majecty/5ea039f8dd507b001a4eec95 When you run the repl, you will see this error message:

UnexpectedError: 
expected 1 to be 1, 'hi'
  The assertion does not have a matching signature for:
    <number> to be <number> <string>
  did you mean:
    <any> [not] to be <any>
    <string> [not] to be <string>
+0 -347

8 comments

4 changed files

majecty

pr closed time in 14 days

PullRequestReviewEvent

pull request commentmochajs/mocha

Fix the usage of expect(a, 'to be', b)

build failure unrelated. may have to do with needing to rebase onto master, but not necessary

majecty

comment created time in 14 days

issue commentnodejs/package-maintenance

Suggest ignoring a vulnerability by the package maintainer

I want to know if my lib/app is actually hitting vulnerable code, and cannot envision being satisfied with any solution that falls short of this. squelching warnings for every vuln that comes up is still extra work. I don't want extra work.

also: I want to emphasize the difficulty of solving the above problem. it is not as simple as code coverage or static analysis. (but either of those things would get the false positive rate down!)

yet, if we were able to reduce the number of times a maintainer (or downstream consumer) must step in to make a change, then we have made progress. personally, I'd rather see a move in this direction. it's less disruptive to spend 25 minutes resolving one problem than to spend 5 minutes each resolving 5 problems.

take this with a grain of salt. npm, snyk, etc will decide if it is worth throwing resources at. (also: excuse me; I am a curmudgeon. it is good to see us trying to work together on this.)

naugtur

comment created time in 14 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 the [`'warning'` event][process_warning] and the [`emitWarning()` method][process_emit_warning] for more information about this flag's behavior. +## `process.parseArgs([argv[, options]])`+<!-- YAML+added: REPLACEME+-->++* `argv` {Array<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:+  * `expectsValue` {Array<string>|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 `process.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 = process.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 = process.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 `process.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.,+    `process.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.++`process.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.

yeah it's wrong. fixed

boneskull

comment created time in 14 days

PullRequestReviewEvent

Pull request review commentnodejs/node

util: add util.parseArgs()

 the [`'warning'` event][process_warning] and the [`emitWarning()` method][process_emit_warning] for more information about this flag's behavior. +## `process.parseArgs([argv[, options]])`+<!-- YAML+added: REPLACEME+-->++* `argv` {Array<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:+  * `expectsValue` {Array<string>|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 `process.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 = process.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 = process.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 `process.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']`)

it becomes true; updated docs to reflect this.

boneskull

comment created time in 14 days

PullRequestReviewEvent

push eventboneskull/node

Christopher Hiller

commit sha 4dbdca31b8056b40949cbc0cb6db91182454515e

add note about Flags dropping string values

view details

push time in 14 days

push eventboneskull/node

Christopher Hiller

commit sha 1d5cd77b9689c27b39f902b0b9ca46df6af5ff6e

doc formatting tweaks

view details

Christopher Hiller

commit sha d64e82aac326feb6288a25aa3d8799c8bf1daa2a

docstring tweaks

view details

push time in 14 days

Pull request review commentnodejs/node

util: add util.parseArgs()

 the [`'warning'` event][process_warning] and the [`emitWarning()` method][process_emit_warning] for more information about this flag's behavior. +## `process.parseArgs([argv[, options]])`+<!-- YAML+added: REPLACEME+-->++* `argv` {Array<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:+  * `expectsValue` {Array<string>|string} (Optional) One or more argument+    strings which _expect a value_ when present

I've addressed this somewhat, but I find the linked documentation too terse. 🤷

boneskull

comment created time in 14 days

PullRequestReviewEvent

pull request commentnodejs/node

util: add util.parseArgs()

The documentation is now aligned with the API. Someone from @nodejs/documentation might want to take a gander though; I'm not sure about:

  • rules around using headers and anchor links
  • rules around formatting of JS types (e.g., when to use Array or array or {Array})
boneskull

comment created time in 14 days

more