Code Monkey home page Code Monkey logo

yargs-parser's Introduction

Yargs

Yargs be a node.js library fer hearties tryin' ter parse optstrings


ci NPM version js-standard-style Coverage Conventional Commits Slack

Description

Yargs helps you build interactive command line tools, by parsing arguments and generating an elegant user interface.

It gives you:

  • commands and (grouped) options (my-program.js serve --port=5000).
  • a dynamically generated help menu based on your arguments:
mocha [spec..]

Run tests with Mocha

Commands
  mocha inspect [spec..]  Run tests with Mocha                         [default]
  mocha init <path>       create a client-side Mocha setup at <path>

Rules & Behavior
  --allow-uncaught           Allow uncaught errors to propagate        [boolean]
  --async-only, -A           Require all tests to use a callback (async) or
                             return a Promise                          [boolean]
  • bash-completion shortcuts for commands and options.
  • and tons more.

Installation

Stable version:

npm i yargs

Bleeding edge version with the most recent features:

npm i yargs@next

Usage

Simple Example

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')
const argv = yargs(hideBin(process.argv)).parse()

if (argv.ships > 3 && argv.distance < 53.5) {
  console.log('Plunder more riffiwobbles!')
} else {
  console.log('Retreat from the xupptumblers!')
}
$ ./plunder.js --ships=4 --distance=22
Plunder more riffiwobbles!

$ ./plunder.js --ships 12 --distance 98.7
Retreat from the xupptumblers!

Note: hideBin is a shorthand for process.argv.slice(2). It has the benefit that it takes into account variations in some environments, e.g., Electron.

Complex Example

#!/usr/bin/env node
const yargs = require('yargs/yargs')
const { hideBin } = require('yargs/helpers')

yargs(hideBin(process.argv))
  .command('serve [port]', 'start the server', (yargs) => {
    return yargs
      .positional('port', {
        describe: 'port to bind on',
        default: 5000
      })
  }, (argv) => {
    if (argv.verbose) console.info(`start server on :${argv.port}`)
    serve(argv.port)
  })
  .option('verbose', {
    alias: 'v',
    type: 'boolean',
    description: 'Run with verbose logging'
  })
  .parse()

Run the example above with --help to see the help for the application.

Supported Platforms

TypeScript

yargs has type definitions at @types/yargs.

npm i @types/yargs --save-dev

See usage examples in docs.

Deno

As of v16, yargs supports Deno:

import yargs from 'https://deno.land/x/yargs/deno.ts'
import { Arguments } from 'https://deno.land/x/yargs/deno-types.ts'

yargs(Deno.args)
  .command('download <files...>', 'download a list of files', (yargs: any) => {
    return yargs.positional('files', {
      describe: 'a list of files to do something with'
    })
  }, (argv: Arguments) => {
    console.info(argv)
  })
  .strictCommands()
  .demandCommand(1)
  .parse()

ESM

As of v16,yargs supports ESM imports:

import yargs from 'yargs'
import { hideBin } from 'yargs/helpers'

yargs(hideBin(process.argv))
  .command('curl <url>', 'fetch the contents of the URL', () => {}, (argv) => {
    console.info(argv)
  })
  .demandCommand(1)
  .parse()

Usage in Browser

See examples of using yargs in the browser in docs.

Community

Having problems? want to contribute? join our community slack.

Documentation

Table of Contents

Supported Node.js Versions

Libraries in this ecosystem make a best effort to track Node.js' release schedule. Here's a post on why we think this is important.

yargs-parser's People

Contributors

bcoe avatar boneskull avatar coreyfarrell avatar elas7 avatar elsbree avatar eomm avatar github-actions[bot] avatar greenkeeperio-bot avatar henderea avatar iilei avatar jkrems avatar jly36963 avatar juergba avatar laggingreflex avatar ljharb avatar lrlna avatar markbirbeck avatar maxrimue avatar mike111177 avatar mleguen avatar nexdrew avatar novemberborn avatar pvdlg avatar qmarkc avatar release-please[bot] avatar renovate[bot] avatar ruimarques avatar ruyadorno avatar ssonal avatar zyrolasting avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yargs-parser's Issues

A coerce function runs again for each alias

The coerce function for an argument with an alias will run multiple times, the initial run and then once more per alias.

I only noticed as I was using the file coercion example and reading a largish file.

let argv = require('yargs')
  .alias('file', 'f2')
  .alias('file', 'f3')
  .coerce('file', function (arg) {
    console.log('reading file', arg)
    return require('fs').readFileSync(arg, 'utf8')
  })
  .argv

then

$ node testyargs.js  --file test
reading file test
reading file test
reading file test

from yargs/yargs#729

wrong behavior when flatten-duplicate-arrays and duplicate-arguments-array are enabled

@nexdrew pointed out this edge-case:

when you enable both flatten-duplicate-arrays and duplicate-arguments-array are enabled

{
  "yargs": {
    "flatten-duplicate-arrays": false,
    "duplicate-arguments-array": false
  }
}

Running:

node test.js -x 1 2 3 -x 2 3 4

results in:

{ _: [],
  x: [ [ '1', '2', '3' ], [ '2', '3', '4' ] ],
  '$0': 'test.js' }

It seems like it would be more consistent with this new API for the result to be x: ['2', '3', '4']

CC: @laggingreflex if you're looking for your next contribution to yargs, would love help adding a test and fix for this.

is this repository still maintained?

I wonder if it makes sense to contribute to this repository anymore as there are quite a few pull requests waiting for response ofthe maintainers for months (including two pull requests by myself).

@bcoe do you need support with maintaining this repository?

Default value should be used when the flag is specified with no value

Actual:

yargs(['--foo'], {number: ['foo'], default: {foo: 1}});
//=> { _: [], foo: undefined }

Expected:

yargs(['--foo'], {number: ['foo'], default: {foo: 1}});
//=> { _: [], foo: 1 }

Applies to string and number.

Alternatively, it could throw, since --foo is technically an incorrect value, but that might be too opinionated for yargs-parser.

Problem parsing number alias

Non-number alias

var argv = require("yargs-parser")(process.argv.slice(2), {
  alias: { z: "zero" },
  default: { zero: false }
});

console.log(argv);
$ node example.js --zero
{ _: [], zero: true, z: true }
$ node example.js -z
{ _: [], z: true, zero: true }

Number alias

var argv = require("yargs-parser")(process.argv.slice(2), {
  alias: { 0: "zero" },
  default: { zero: false }
});

console.log(argv);
$ node example.js --zero
{ '0': true, _: [], zero: true }
$ node example.js -0
{ '0': false, _: [ -0 ], zero: false }

For more context check sindresorhus/meow#89

Do not set boolean to `false` if flag is not in args

Currently when defining a boolean option, without specifying its default value, if the user doesn't set the corresponding arg the value is set to false.

Therefore its impossible to know if users set the flag to false or this they just omitted it.

This is problematic in situation in which you want to merge the options returned by yargs-parser with another object options (from a config file for example) with Object.assign or similar.
Typically you would merge options so the CLI args take precedence over the config file. So users can specify their config and override it in development mode by passing an option to the cli.

In such situation, if the user do not pass the flag in the CLI, the merged options will always have false for this flag, as yargs-parser option have it set to false and it override what's in the config.

Ideally the value of a boolean flag should be undefined when the user doesn't pass the flag in the CLI.

Would be open to a PR that implement such behavior?

Omit original key when camel cased key is added

In node example.js --foo-bar, it returns { _: [], 'foo-bar': true, fooBar: true }. Can it return { _: [], fooBar: true } because I do some external validation of the returned object to ensure that everything is right. And I would have to duplicate the validation for fooBar to foo-bar. It would be better if both weren't to appear in the returned object.

Setting an argument to both array and number gives unexpected results

Calling this example code:

const yargsParser = require('yargs-parser');

const argv = yargsParser(process.argv.slice(2), {
	array: ['arr'],
});

console.log(JSON.stringify(argv, null, 2));

with these arguments:

node example.js --arr foo 2 bar

gives (as expected) the following output:

{
  "_": [],
  "arr": [
    "foo",
    2,
    "bar"
  ]
}

Adjusting the parsing options to treat the array as strings:

const yargsParser = require('yargs-parser');

const argv = yargsParser(process.argv.slice(2), {
	array: ['arr'],
	string: ['arr'],
});

console.log(JSON.stringify(argv, null, 2));

gives the following output (also as expected):

{
  "_": [],
  "arr": [
    "foo",
    "2",
    "bar"
  ]
}

However, if I tell it to treat the array as numbers:

const yargsParser = require('yargs-parser');

const argv = yargsParser(process.argv.slice(2), {
	array: ['arr'],
	number: ['arr'],
});

console.log(JSON.stringify(argv, null, 2));

then I would expect to get all array elements parsed as numbers:

{
  "_": [],
  "arr": [
    null,
    2,
    null
  ]
}

Instead, I get this result:

{
  "_": [],
  "arr": [
    null
  ]
}

Notably, this is also the case if all array elements are valid numbers:

node example.js --arr 1 2 3

gives the same result:

{
  "_": [],
  "arr": [
    null
  ]
}

Stop parsing after first unknown argument

Looking at the docs this seems to be a feature request as I cant see support for this behaivour ;)

It should be similar to minimist's stopEarly. Currently with yargs-parser you can only 'stop' parsing arguments by proving --. But thats not always 'handy' or 'nice'.

With minimist's stopEarly the parsing of arguments just stops when an argument is encountered that is not listed anywhere. That way you can easily 'prefix' another app with your app.

See e.g. a program as nyc, which you can just prefix your test program with and which then automatically processes the results of your tests.

odd behavior of narg:2 versus duplicate-arguments-array:false

const P = require('yargs-parser')
P('foo -p x y', { narg: { p: 2 } })
{ _: [ 'foo' ], p: [ 'x', 'y' ] }

i.e. this results in the expected {x:'y'} binding.

whereas:

P('foo -p x y', { narg: { p: 2 }, configuration: {  'duplicate-arguments-array': false } })
{ _: [ 'foo' ], p: 'y' }

which seems buggy, and contrary to the documentation. i would expect the resulting binding to be the same in both cases.

Empty Strings cause "Cannot read property 'match' of undefined"

Related to @ilatypov's comment on #93:

Passing an empty string into yargs-parser results in an error:

let parse = require("yargs-parser");
let options = parse("a command containing '' an empty string");

Results in:

TypeError: Cannot read property 'match' of undefined
    at parse (/home/runner/node_modules/yargs-parser/index.js:140:13)
    at Parser (/home/runner/node_modules/yargs-parser/index.js:822:16)
    at evalmachine.<anonymous>:2:15
    at Script.runInContext (vm.js:74:29)
    at Object.runInContext (vm.js:182:6)
    at evaluate (/run_dir/repl.js:133:14)
    at ReadStream.<anonymous> (/run_dir/repl.js:116:5)
    at ReadStream.emit (events.js:180:13)
    at addChunk (_stream_readable.js:274:12)
    at readableAddChunk (_stream_readable.js:261:11)

See the following repl.it:
https://repl.it/@jacksdrobinson/YargsParserBugReplication

Preserve casing with ENV

From the API page API page

With .env([prefix]), the environment variable casing is converted from upper case to lower; is there an option to preservice upper casing?

Overriding default nested values

Hi there! Thanks for the awesome lib!

I'm trying to use nested fields in the default config to structure it better. But it seems that when I try to override one of the nested fields, it overrides the whole nested object.

Is it expected or am I doing something wrong?

Here is an example:

const defaultConfig = {
  topField1: {
    nestedField1: 'hello',
    nestedField2: 'world'
  },
  topField2: 'great'
}

console.log('Default config: ', defaultConfig)

const yargsParser = require('yargs-parser')
const configAfterYargs = yargsParser(process.argv.slice(2), {
  default: defaultConfig
})

console.log('After yargs: ', configAfterYargs)
$ node yargs-nested-example.js --topField2 cool --topField1.nestedField2 planet
Default config:  { topField1: { nestedField1: 'hello', nestedField2: 'world' },
  topField2: 'great' }
After yargs:  { _: [],
  topField2: 'cool',
  topField1: { nestedField2: 'planet' } }

Now, topField1.nestedField1 has disappeared.

Inconsistent array parsing(string values are wrapped in an array instead of parsed)

Original issue: yargs/yargs#789.

The string values are parsed correctly in case of boolean or number values, but are not in case of array. Something like https://github.com/mccormicka/string-argv could be used to parse strings into arrays(simple parsing might not work because quotes must be considered, too).

Passed through cli:

const argv = require('yargs')
  .options({
    arr: {
      type: 'array',
    },
  })
  .argv;

console.log('argv', argv);

$ node ./test.js --arr foo bar
Outputs: argv { _: [], arr: [ 'foo', 'bar' ], '$0': 'test.js' }

Passed through .config()

const argv = require('yargs')
  .config({
    arr: 'foo bar',
  })
  .options({
    arr: {
      type: 'array',
    },
  })
  .argv;

console.log('argv', argv);

$ node ./test.js
Outputs: argv { _: [], arr: [ 'foo bar' ], '$0': 'test.js' }

[email protected]

feat: should we provide a way for folks to filter whether or not an argument should be appended to an array

If you have a flag that takes an array, how to make it differentiate between the values that it's supposed take and those that should just be positional arguments?

For Eg.:

create-index --filetype .js .jsx ./src

Here filetype should only take .js .jsx and ./src should be a positional argument.

It seems this isn't currently possible, right? I haven't come across this kind of use case before so I'm not sure what should the solution to this be. Is this something that should even be solved at yargs level, or should the end-user just be advised to use the cli in a way to avoid this issue altogether (create-index ./src --filetype .js .jsx)

Parsing Issue

The parser seems to remove quotes before passing in any specific options.
My use case is creating a sort of evaluation command which parses in certain options from the user like so:
User: someExampleFunction('hello')
But, I get this:
Error: ReferenceError: hello is not defined

The actual parsed string is someExampleFunction(hello).
Is there any way to get around this and stop it removing quotes before I add something like --some-option "testing" (Where I would want it to set some-option to "testing")?

Positional argument, build, and argument separator behavior

Hi!

I'm using yargs to build a CLI. The CLI is made up of commands. The application is initialized like this:

import yargs from 'yargs';

yargs
  .commandDir('cmds')
  .demandCommand()
  .help()
  .argv;

The cmds directory contains various commands and one of them has a positional argument that should be treated as string as it is sometimes composed only by numbers, it must remains a string.

Here's how the command is written:

export const command = 'setup <client_id> <api_key>';
export const builder = yargs => yargs.string('client_id');
export const handler = setup;

Here's the odd behavior, client_id is coerced as string or as number depending on how the application is executed:

$ npx babel-node ./src setup 012 test
client_id 12
$ npx babel-node ./src -- setup 012 test
client_id 012

Using babel-node doesn't change anything, after being transpiled to ES5, the issue remains. I don't want my user to have to use the argument separator. What can I do better? Is it a bug in yargs?

Thanks in advance,
Fabian

Disabling "flatten-duplicate-arrays" leads to unexpected results

Calling this example code:

const yargsParser = require('yargs-parser');

const argv = yargsParser(process.argv.slice(2), {
	array: ['arr'],
	configuration: {
		'flatten-duplicate-arrays': false,
	},
});

console.log(JSON.stringify(argv, null, 2));

with these arguments:

node example.js --arr One Two Three --arr Four Five Six --arr Seven Eight Nine --arr Ten Eleven Twelve

I would expect the following output:

{
  "_": [],
  "arr": [
    [
      "One",
      "Two",
      "Three"
    ],
    [
      "Four",
      "Five",
      "Six"
    ],
    [
      "Seven",
      "Eight",
      "Nine"
    ],
    [
      "Ten",
      "Eleven",
      "Twelve"
    ]
  ]
}

However, instead I get this output:

{
  "_": [],
  "arr": [
    [
      [
        [
          "One",
          "Two",
          "Three"
        ],
        [
          "Four",
          "Five",
          "Six"
        ]
      ],
      [
        "Seven",
        "Eight",
        "Nine"
      ]
    ],
    [
      "Ten",
      "Eleven",
      "Twelve"
    ]
  ]
}

This doesn't seem right to me. Is this the expected behaviour? (If so, it is not apparent from the documentation, in my opinion.)

parsing args issue if value starts with dash(-) character

Steps to reproduce

Save this snippet as example.js

var argv = require('yargs-parser')(process.argv.slice(2))
console.log(argv)

If we run the file by passing these arguments, then we are getting expected result of both arguments i.e foo as 33 and bar as hello

$ node example.js --foo=33 --bar "hello"
{ _: [], foo: 33, bar: 'hello' }

But, if we pass bar argument value whose starting character is -, then output changes a lot, and it's also not a expected one

$ node example.js --foo=33 --bar "-hello"
{ _: [],
  foo: 33,
  bar: true,
  h: true,
  e: true,
  l: [ true, true ],
  o: true }

Here, foo argument has correct value but bar argument value is now boolean.

Expected output in both instructions
{ _: [], foo: 33, bar: 'hello' }

Incorrect `default` type should not be allowed

The parser should not allow setting the incorrect type for default.

yargs([], {number: ['foo'], default: {foo: 'x'}});
//=> { _: [], foo: 'x' }

The above should not be allowed as we defined foo as a number, but the default is set to a string. This should throw an error to prevent mistakes.

compiling yargs-parser with Webpack generates warnings

Hi guys !

So my use-case for bundling NodeJs scripts with Webpack is that I need to embed those scripts into machines without internet access (so the bundle has to be ready, no npm install, ...).

Now, from what i understood, Webpack doesn't like "dynamic requires".

Here is the warning emitted by Webpack when trying to compile a script with yargs-parser :

image

I believe the warning comes from this line : https://github.com/yargs/yargs-parser/blob/master/index.js#L451

Removing the dynamic require also removes the warning.

So i was wondering if it would be possible to replace this dynamic require by a readFile or something similar.

This is the only thing preventing me from switching from minimist to yargs-parser.
Thanks for your consideration !

array with alias not working well

// test.js
console.log(
  require('yargs-parser')(process.argv.slice(2), {
    'alias': {
      'f': 'files'
    },
    'array': ['files']
  })
);
node test.js -f  // -> output: { _: [], f: [ true ], files: [ true ] } (this is broken!)
node test.js --files // -> output: { _: [], files: [], f: [] }
node test.js -f -y // -> output: { _: [], f: [], files: [], y: true }
node test.js --files -y // -> output: { _: [], f: [], files: [], y: true }

I think it should be a bug...

Only match negated booleans for bool options that exist

I have a --no-install argument I pass in to a script to disable installing, using the following option:

option('no-install', {
    alias: 'n',
    default: false,
    description: "Don't run install first",
    type: 'boolean',
  })

However, instead of giving me noInstall: true as I would expect, I get install: false and noInstall: false. This happens even though I have not defined a option called install. IMHO there are two things wrong with this: First, the negated bool test has higher precedence then matching against an existing option, and secondly it's perfectly happy to accept --no-foo-bar even if I have not configured that as an option. If the second one is a requirement for some reason (because we want to allow for arbitrary options), at least maybe move the test after checking if it's a configured option?

Invalid transformation of upper camelcase fields

My config.json file contains the following:

{
    "models": [ {
        "id": 42,
        "UserUid": "e40d18c5-ba1d-43f5-90a2-a8e45547ff94"
    } ]
}

However, when loaded via Yargs, I get the following:

{
    "models": [ {
        "id": 42,
        "userUid": "e40d18c5-ba1d-43f5-90a2-a8e45547ff94"
    } ]
}

Notice how the UserUid has been changed into userUid, which breaks various pieces of code.

Of course, I could disable camel-case-expansion, but then I would lose the --init-server to initServer transform too, which I'd like to keep. Could it be possible to add an option to preserve the case of a word's first letter, so that upper camelcase strings would work just as well as lower camelcase strings ?

RangeError: Maximum call stack size exceeded

I initially encountered the below error via executing nyc, but opening the issue here as the stack trace indicates the error tracing back to yargs-parser.

Stack trace: (note I obfuscated the first part of my local paths with ****)

> nyc --nycrc-path config/unit/.nycrc npm run test:unit
****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:669
    toCheck.forEach(function (key) {
            ^

RangeError: Maximum call stack size exceeded
    at Array.forEach (<anonymous>)
    at checkAllAliases ****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:669:13)
    at setArg (****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:392:9)
    at ****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:502:11
    at Array.forEach (<anonymous>)
    at setConfigObject (****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:488:25)
    at ****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:497:9
    at Array.forEach (<anonymous>)
    at setConfigObject (****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:488:25)
    at ****\node_modules\nyc\node_modules\yargs\node_modules\yargs-parser\index.js:497:9

My Environment:

  • Windows 10
  • node version: 8.9.4
  • npm version: 5.6.0
  • Repo has dependency on nyc, version: 11.7.1, which locally has deps:
    • yargs version: 11.1.0
    • yargs-parser version: 8.1.0

Back on the nyc configuration side, we've created a shareable/reusable nyc config module as described in the nyc docs and we are using that nyc config module in some of our repos, including the repo where we encountered the above error.

About our shared nyc-config module:

  • We defined a few different nyc config files in our module (via json files).
  • The module itself exports a javascript file, which exports those different configs (this allows us to utilize the various configs both from our .nycrc files and programmatically).

Our original js file that was exported by the shared/reusable nyc config module (that caused the above error when we ran nyc) looked like this:

const completeCoverageConfig = require('./complete-coverage.json');

module.exports = completeCoverageConfig;
module.exports.completeCoverageConfig = completeCoverageConfig;
module.exports.baseConfig = require('./base.json');
module.exports.partialCoverageConfig = require('./partial-coverage.json');

After getting the above error, we updated that js file exported by the shared nyc config module to remove the extra property pointing to the same config, and that fixed things (we do not get the Range/Call stack error now when running nyc with this nyc-config module):

module.exports = require('./complete-coverage.json');
module.exports.baseConfig = require('./base.json');
module.exports.partialCoverageConfig = require('./partial-coverage.json');

Our updated version is working well and we can certainly live with current state. Guessing the original configuration may be a user issue on our side, but thought I'd share the stack trace just in case..

Option values cannot be negative numbers

It's not currently possible to set option values to negative numbers (w/o using =), as demonstrated in this diff to the tests:

diff --git i/test/yargs-parser.js w/test/yargs-parser.js
index e290110..07d7335 100644
--- i/test/yargs-parser.js
+++ w/test/yargs-parser.js
@@ -116,6 +116,7 @@ describe('yargs-parser', function () {
       '-z', '1e7',
       '-w', '10f',
       '--hex', '0xdeadbeef',
+      '--negative', '-1',
       '789'
     ])
     argv.should.have.property('x', 1234).and.be.a('number')
@@ -123,6 +124,7 @@ describe('yargs-parser', function () {
     argv.should.have.property('z', 1e7).and.be.a('number')
     argv.should.have.property('w', '10f').and.be.a('string')
     argv.should.have.property('hex', 0xdeadbeef).and.be.a('number')
+    argv.should.have.property('negative', -1).and.be.a('number')
     argv.should.have.property('_').and.deep.equal([789])
     argv._[0].should.be.a('number')
   })

I'm actually more interested in being able to parse an array of numbers, some of which may be negative (e.g. --bounds "-180 -90 180 90", possibly even unquoted), but this appears to be the first snag along that path.

Inconsistent parsing of arrays with dot-notation when argument order is switched

The way an array argument is parsed changes depending on whether I parse --config.compression=store --config ./electron.config.json vs. --config ./electron.config.json --config.compression=store

When I run:

var argv = require("yargs-parser")('--config.compression=store --config ./electron.config.json')

The value of argv.compression is

[
  {
    "compression": "store"
  },
  "./electron.config.json"
]

But when I swap the arguments and run:

var argv = require("yargs-parser")('--config ./electron.config.json --config.compression=store')

The value of argv.compression is

"\"./electron.config.json\""

I would expect them both to equal the result of the first command. Is there a reason for this, or is it a bug?

yargs not passing string correctly

describe('TokenizeArgString', function () {
  it.only('....handles quoted string', function () {
    var args = tokenizeArgString('-q sku="invalid"')
    args[0].should.equal('-q') // passes
    args[1].should.equal('sku="invalid"') //fails
  })
})

This test fails on this module. Not sure how to fix it.

camelcase library causes uglify to fail

The camelcase library is ES6. When you use this project with tools like Webpack and Uglify they throw errors because it can't parse the camelcase library.

Arrays doesn't seem to work

Or am I missing something?

Here is my index.js file:

const argv = require("yargs-parser")(process.argv.slice(2));
console.log(argv);

Tests:

$ node index.js -a 1 2 3
Yields:
{ _: [ 2, 3 ], a: 1 }

$ node index.js -a 1 2 -a 3
Yields:
{ _: [ 2 ], a: [ 1, 3 ] }

I thought maybe it is an expected behavior but then I tried example from the readme:
$ node index.js -x 1 2 -x 3 4
Result:
{ _: [ 2, 4 ], x: [ 1, 3 ] }
When it should be { _: [], x: [1, 2, 3, 4] } according to the documentation. ๐Ÿค”

What can be the problem?

node v9.4.0
yargs-parser v8.1.0

Optional choices for array

I have a config like this:

filetype: {
  choices: ['.js', '.jsx'],
  type: 'array'
},
recursive: {
  type: 'boolean'
}, 

So this works:

create-index --filetype .js .jsx --recursive ./src

But this throws an error:

create-index --filetype .js .jsx ./src
Invalid values:
  Argument: filetype, Given: "./src", Choices: ".js", ".jsx"

There should be an option to make the choices be "optional" rather than throw an error. If it doesn't find a match it should consider the rest of the arguments to be positional arguments. This can be especially useful for arrays as shown in above example. It should throw (in case of an array) only if the first argument doesn't match.

This could possibly address #219

camelCasedFlag is an Array if `.boolean('camel-cased-flag')` is called

copy of yargs/yargs#644

repro test case:


it('should expose camelCased boolean property for dash-separated-option', function () {
  var parse = parser(['--foo-bar'])
  parse.should.have.property('foo-bar', true).and.be.a('boolean')
  parse.should.have.property('fooBar', true).and.be.a('boolean')
})
it('should expose camelCased boolean property for dash-separated-option marked as a boolean', function () {
  var parse = parser(['--foo-bar'], {
    boolean: ['foo-bar']
  })
  parse.should.have.property('foo-bar', true).and.be.a('boolean')
  parse.should.have.property('fooBar', true).and.be.a('boolean') // FAIL
})

this logs

  1 failing

  1) yargs-parser should expose camelCased boolean property for dash-separated-option marked as a boolean:
     AssertionError: expected { Object (_, foo-bar, ...) } to have a property 'fooBar' of true, but got [ false, true ]
      at Context.<anonymous> (test\yargs-parser.js:175:23)

I wanted to fix it myself but code is not that easy to follow so I guest I'll stop here ;]

Edit: I put it as a commit here jakub-g@51c511d

Consider better support for arrays with coercion

Problem

Through testing of the coerce option, I noticed that the coercion function is called for each element in the array instead of once for the entire array, regardless of the array option. This makes it impossible to coerce the array-as-a-whole within a coercion function.

Here's an example:

var parse = require('yargs-parser')
var result = parse.detailed(process.argv.slice(2), {
  array: ['add'],
  coerce: {
    add: function (arg) {
      return arg.map(Number).reduce(function (x, y) {
        return x + y
      }, 0)
    }
  }
})
console.log(result)
$ node coerce.js --add 1 2 3
{ argv: { _: [], add: [ '1', '2', '3' ] },
  error: 
   TypeError: arg.map is not a function
       ... snip stack...,
  aliases: { add: [] },
  newAliases: {},
  configuration: 
   { 'short-option-groups': true,
     'camel-case-expansion': true,
     'dot-notation': true,
     'parse-numbers': true,
     'boolean-negation': true } }

Proposal

Defer coercion (at least for arrays) until after initial parsing is done

This would allow the above example to work as is, with the following result:

$ node coerce.js --add 1 2 3
{ argv: { _: [], add: 6 },
  error: null,
  aliases: { add: [] },
  newAliases: {},
  configuration: 
   { 'short-option-groups': true,
     'camel-case-expansion': true,
     'dot-notation': true,
     'parse-numbers': true,
     'boolean-negation': true } }

Note that no context is lost with this approach because the coercion can always iterate over the array of values if it wishes to coerce them individually.

A possible alternative could be to pass the existing value (from argv) to the coerce function as a second parameter, to potentially allow coercion to "build up" or "reduce to" a desired value, but I think this could lead to a lot of confusion and would argue against it.

setConfigObject() crashes on null value for object key

PR on #108. Given the following entry point...

require('yargs')
    .config({key: null})
    .commandDir(`${__dirname}/tasks`)
    .demandCommand()
    .help()
    .argv;

You get this stack trace:

/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:476
    Object.keys(config).forEach(function (key) {
           ^

TypeError: Cannot convert undefined or null to object
    at Function.keys (<anonymous>)
    at setConfigObject (/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:476:12)
    at /home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:485:9
    at Array.forEach (<anonymous>)
    at setConfigObject (/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:476:25)
    at /home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:500:7
    at Array.forEach (<anonymous>)
    at setConfigObjects (/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:499:19)
    at parse (/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:286:3)
    at Function.Parser.detailed (/home/sage/Code/redacted/node_modules/yargs/node_modules/yargs-parser/index.js:776:10)
    at Object.parseArgs [as _parseArgs] (/home/sage/Code/redacted/node_modules/yargs/yargs.js:967:27)
    at Object.get [as argv] (/home/sage/Code/redacted/node_modules/yargs/yargs.js:957:21)
    at Object.<anonymous> (/home/sage/Code/redacted/ui:18:5)
    at Module._compile (module.js:624:30)
    at Object.Module._extensions..js (module.js:635:10)
    at Module.load (module.js:545:32)

It seems this happens because typeof null === 'object' and thus triggers recursion in setConfigObject(), namely on the condition in index.js:482

// if the value is an inner object and we have dot-notation
// enabled, treat inner objects in config the same as
// heavily nested dot notations (foo.bar.apple).
if (typeof value === 'object' && !Array.isArray(value) && configuration['dot-notation']) {
	// if the value is an object but not an array, check nested object
	setConfigObject(value, fullKey)
} else { /* ... */ }

Please explain how to convert hyphenated arguments to camelcase

I cannot seem to find a way to accept hyphenated arguments and convert them to a camelCase version. Is that supported by the module?

I have the following example:

module.exports = {
  command: 'create <emailAddress>',
  describe: 'Create a user account',
  builder: {
    password: {
      alias: 'p',
      desc: 'User password',
      demandOption: true,
    },
    accountAccess: {
      alias: 'a',
      demandOption: true,
      requiresArg: true,
      default: 'r',
      choices: ['r', 'rw'],
    },
    firmwareAccess: {
      alias: 'f',
      requiresArg: true,
      default: 'r',
      choices: ['r', 'rw'],
    }
  },
  handler(argv) {
...

I'm pretty sure the standard will be to accept account-access instead of accountAccess. Would that be possible?

Thanks.

normalize seems to override coerce callback result

It seems that when the two property are combined, normalize overrides the coerced value with the normalized version of the original value of the option.

Minimal nodejs snippet to reproduce the issue:

var yargs = require('yargs');
var path = require('path');

var argv = yargs.option('source-dir', {
  normalize: true,
  coerce: path.resolve
}).argv;

console.log("result", {
  sourceDir: argv.sourceDir,
  resolvedSourceDir: path.resolve(argv.sourceDir)
});
$ node test-normalize-coerce.js --source-dir ../src/../src
result { sourceDir: '../src',
  resolvedSourceDir: '/resolved/dir/src' }

allow configuration to be passed into yargs-parser

By default yargs-parser and yargs load configuration from a yargs stanza in your package.json. This can be used to toggle on and off various parsing features.

We should also accept an opts.configuration option, which would take precedence. This would allow a library consuming yargs-parser to:

  • load configuration from its own stanza.
  • turn off feature toggling if this is not something they want in their own library.
  • this still allows us to keep the default configuration loading behavior in yargs-parser and out of yargs.

Arrays and values with hyphens

I need to pass in an array of values that have hyphens. I can't seem to figure out the required syntax.

node app.js --arrOption "-val1" "-val2" "-val3"
Result: []
node app.js --arrOption "-val1" --arrOption "-val2" --arrOption "-val3"
Result: [ [], [] ]
node app.js --arrOption="-val1" --arrOption="-val2" --arrOption="-val3"
Result: [ [], '-val3' ]

Desired result:

[ '-val1', '-val2', '-val3' ]

How can I achieve this?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.