Git Product home page Git Product logo

nopt's Introduction

If you want to write an option parser, and have it be good, there are two ways to do it. The Right Way, and the Wrong Way.

The Wrong Way is to sit down and write an option parser. We've all done that.

The Right Way is to write some complex configurable program with so many options that you hit the limit of your frustration just trying to manage them all, and defer it with duct-tape solutions until you see exactly to the core of the problem, and finally snap and write an awesome option parser.

If you want to write an option parser, don't write an option parser. Write a package manager, or a source control system, or a service restarter, or an operating system. You probably won't end up with a good one of those, but if you don't give up, and you are relentless and diligent enough in your procrastination, you may just end up with a very nice option parser.

USAGE

// my-program.js
var nopt = require("nopt")
  , Stream = require("stream").Stream
  , path = require("path")
  , knownOpts = { "foo" : [String, null]
                , "bar" : [Stream, Number]
                , "baz" : path
                , "bloo" : [ "big", "medium", "small" ]
                , "flag" : Boolean
                , "pick" : Boolean
                , "many1" : [String, Array]
                , "many2" : [path, Array]
                }
  , shortHands = { "foofoo" : ["--foo", "Mr. Foo"]
                 , "b7" : ["--bar", "7"]
                 , "m" : ["--bloo", "medium"]
                 , "p" : ["--pick"]
                 , "f" : ["--flag"]
                 }
             // everything is optional.
             // knownOpts and shorthands default to {}
             // arg list defaults to process.argv
             // slice defaults to 2
  , parsed = nopt(knownOpts, shortHands, process.argv, 2)
console.log(parsed)

This would give you support for any of the following:

$ node my-program.js --foo "blerp" --no-flag
{ "foo" : "blerp", "flag" : false }

$ node my-program.js ---bar 7 --foo "Mr. Hand" --flag
{ bar: 7, foo: "Mr. Hand", flag: true }

$ node my-program.js --foo "blerp" -f -----p
{ foo: "blerp", flag: true, pick: true }

$ node my-program.js -fp --foofoo
{ foo: "Mr. Foo", flag: true, pick: true }

$ node my-program.js --foofoo -- -fp  # -- stops the flag parsing.
{ foo: "Mr. Foo", argv: { remain: ["-fp"] } }

$ node my-program.js --blatzk -fp # unknown opts are ok.
{ blatzk: true, flag: true, pick: true }

$ node my-program.js --blatzk=1000 -fp # but you need to use = if they have a value
{ blatzk: 1000, flag: true, pick: true }

$ node my-program.js --no-blatzk -fp # unless they start with "no-"
{ blatzk: false, flag: true, pick: true }

$ node my-program.js --baz b/a/z # known paths are resolved.
{ baz: "/Users/isaacs/b/a/z" }

# if Array is one of the types, then it can take many
# values, and will always be an array.  The other types provided
# specify what types are allowed in the list.

$ node my-program.js --many1 5 --many1 null --many1 foo
{ many1: ["5", "null", "foo"] }

$ node my-program.js --many2 foo --many2 bar
{ many2: ["/path/to/foo", "path/to/bar"] }

Read the tests at the bottom of lib/nopt.js for more examples of what this puppy can do.

Types

The following types are supported, and defined on nopt.typeDefs

  • String: A normal string. No parsing is done.
  • path: A file system path. Gets resolved against cwd if not absolute.
  • url: A url. If it doesn't parse, it isn't accepted.
  • Number: Must be numeric.
  • Date: Must parse as a date. If it does, and Date is one of the options, then it will return a Date object, not a string.
  • Boolean: Must be either true or false. If an option is a boolean, then it does not need a value, and its presence will imply true as the value. To negate boolean flags, do --no-whatever or --whatever false
  • NaN: Means that the option is strictly not allowed. Any value will fail.
  • Stream: An object matching the "Stream" class in node. Valuable for use when validating programmatically. (npm uses this to let you supply any WriteStream on the outfd and logfd config options.)
  • Array: If Array is specified as one of the types, then the value will be parsed as a list of options. This means that multiple values can be specified, and that the value will always be an array.

If a type is an array of values not on this list, then those are considered valid values. For instance, in the example above, the --bloo option can only be one of "big", "medium", or "small", and any other value will be rejected.

When parsing unknown fields, "true", "false", and "null" will be interpreted as their JavaScript equivalents.

You can also mix types and values, or multiple types, in a list. For instance { blah: [Number, null] } would allow a value to be set to either a Number or null. When types are ordered, this implies a preference, and the first type that can be used to properly interpret the value will be used.

To define a new type, add it to nopt.typeDefs. Each item in that hash is an object with a type member and a validate method. The type member is an object that matches what goes in the type list. The validate method is a function that gets called with validate(data, key, val). Validate methods should assign data[key] to the valid value of val if it can be handled properly, or return boolean false if it cannot.

You can also call nopt.clean(data, types, typeDefs) to clean up a config object and remove its invalid properties.

Error Handling

By default, nopt outputs a warning to standard error when invalid values for known options are found. You can change this behavior by assigning a method to nopt.invalidHandler. This method will be called with the offending nopt.invalidHandler(key, val, types).

If no nopt.invalidHandler is assigned, then it will console.error its whining. If it is assigned to boolean false then the warning is suppressed.

Abbreviations

Yes, they are supported. If you define options like this:

{ "foolhardyelephants" : Boolean
, "pileofmonkeys" : Boolean }

Then this will work:

node program.js --foolhar --pil
node program.js --no-f --pileofmon
# etc.

Shorthands

Shorthands are a hash of shorter option names to a snippet of args that they expand to.

If multiple one-character shorthands are all combined, and the combination does not unambiguously match any other option or shorthand, then they will be broken up into their constituent parts. For example:

{ "s" : ["--loglevel", "silent"]
, "g" : "--global"
, "f" : "--force"
, "p" : "--parseable"
, "l" : "--long"
}
npm ls -sgflp
# just like doing this:
npm ls --loglevel silent --global --force --long --parseable

The Rest of the args

The config object returned by nopt is given a special member called argv, which is an object with the following fields:

  • remain: The remaining args after all the parsing has occurred.
  • original: The args as they originally appeared.
  • cooked: The args after flags and shorthands are expanded.

Slicing

Node programs are called with more or less the exact argv as it appears in C land, after the v8 and node-specific options have been plucked off. As such, argv[0] is always node and argv[1] is always the JavaScript program being run.

That's usually not very useful to you. So they're sliced off by default. If you want them, then you can pass in 0 as the last argument, or any other number that you'd like to slice off the start of the list.

nopt's People

Contributors

ad-si avatar commanderroot avatar dependabot[bot] avatar elidoran avatar github-actions[bot] avatar helio-frota avatar iarna avatar isaacs avatar jonbretman avatar lukekarrys avatar michaelficarra avatar mklement0 avatar othiym23 avatar robertkowalski avatar samjonester avatar shahata avatar silkentrance avatar sintaxi avatar stevenvachon avatar wraithgar avatar zkat 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  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

nopt's Issues

Odd behavior with wrong keys

I have the following case:
long args are
--account / -a
--credentials / -c
--options / -o

now If I pass "--acount bla" (typod) it does not report a unknown key but interprets it as:

"--account --credentials --options bla" which is entirely wrong

Strange parsing results with multiple unknown flags

node-gyp uses any "unknown" flags as custom defines for gyp to use while building a native add-on (i.e. --with-jpeg turns into a 'with_jpeg="true"' variable in gyp).

But if there's two unknown flags in a row, nopt treats the second flag like the value to the first one, rather then treating them as two separate flags.

$ node-gyp install canvas --with-jpeg --with-gif

Produces a gypi file containing:

...
    "with_jpeg": "--with-gif"
...

Which is undesirable :(

abbrev has no '1' version at all

Hi,

If I understand correct, according to http://semver.org/:

'abbrev':'1'

means 'abbrev':'1.0.0', not 'abbrev':'1.x', right?

but abbrev's version starts from 1.0.3.

so actually you were requiring a version that never exists.

Marguerite

path type with no argument appends true to cwd

If nothing is passed, I would think that it should either not be accepted or default to the cwd.

Here is an example

var nopt = require('nopt')
  , path = require('path')
  , knownOpts = { path: path
                }
  , shortHands = { p: ['--path']
                 }
  , parsed = nopt(knownOpts, shortHands, process.argv, 2)

console.log(parsed)

If run like:

$ ./test --path

The output would be:

{ path: '/Users/evan/dev/code/node/tests/nopt_test/true',
  argv: { remain: [], cooked: [ '--path' ], original: [ '-p' ] } }

Can nopt not handle optional arguments to known options?

We have known options:

var knownOptions = {
    '508': String,
    'wcag2': String,
    'devmin': String
};

None of which require an argument.

cli --508 arg508 --wcag argWcag works fine. It results in:
{508: "arg508", wcag: "argWcag"}

However, cli --508 --wcag results in:
{508: "--wcag"}

but we want:
{508: "", wcag: ""}

We've tried making these options be of a custom type that validates the value is not itself a known option. However, that doesn't push the option pack into the parsed options; it just invokes the invalidOption handler and exits.

Is there a way to get this behavior such that the argument to the known options is optional?

[BUG] Boolean arg swallows following arg if it is `false` or `true`

Boolean options should not swallow the following argument if it is false or true. This can occur coincidentally and is probably not what the user wants.

Consider a CLI tool that outputs the size of files, where each file is passed as a positional argument. The -h or --human flag causes it to output human-friendly values. ("1KB" instead of "1024")

$ file-sizes -h *
file-1 1MB
file-2 2.3MB

Now imagine that the files in CWD are "false", "foo", and "bar"

$ file-sizes -h *
foo 1035
bar 345
# Errors: -h flag isn't set; "false" is omitted

For this reason, boolean options should never interpret the following argument as their value.

# following positional argument should *never* be interpreted as a value for the `--human` flag
file-sizes --human true

Users can still pass --human, --no-human, --human=true, or --human=false to explicitly set the flag to true or false.

nopt and WebStorm 11

Hi there!

I have an issue with running Yeoman generator in WebStorm 11. Getting the following error:

events.js:141
      throw er; // Unhandled 'error' event
      ^

TypeError: Cannot read property 'match' of undefined
    at parse (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/nopt/lib/nopt.js:239:12)
    at nopt (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/nopt/lib/nopt.js:40:3)
    at ControllerGenerator.Base.parseOptions (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/yeoman-generator/lib/base.js:345:10)
    at ControllerGenerator.option (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/yeoman-generator/lib/base.js:275:8)
    at ControllerGenerator.Base (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/yeoman-generator/lib/base.js:85:8)
    at new ControllerGenerator (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/generator-sails-rest-api/generators/controller/index.js:43:85)
    at Environment.instantiate (/usr/local/lib/node_modules/yo/node_modules/yeoman-environment/lib/environment.js:297:10)
    at Environment.create (/usr/local/lib/node_modules/yo/node_modules/yeoman-environment/lib/environment.js:274:15)
    at AppGenerator.composeWith (/Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/yeoman-generator/lib/base.js:623:26)
    at /Users/ghaiklor/Library/Caches/WebStorm11/extLibs/yeoman/generators_local/generator-sails-rest-api/node_modules/generator-sails-rest-api/generators/app/steps/default.js:49:11

I'd made a little research and seems that issue in parse method - https://github.com/npm/nopt/blob/master/lib/nopt.js#L228

I'm wondering if this issues is nopt related, Yeoman or WebStorm itself.

[FEATURE] Add a handler for *unknown* options, analogous to `invalidHandler`

Currently (v3.0.1), nopt invariably accepts unknown options and simply adds them to the object returned.

However, a typical use case for a CLI is to abort processing in case an unknown option is specified.

Thus, an .unknownHandler property specifying a function to call on encountering an unknown option would be handy - analogous to the existing .invalidHandler property for handling invalid option values.

I'd be happy to implement this.

[QUESTION] Option to disable auto-negation?

I actually wanted to have a flag called "no-restart", but instead nopt makes me name it "restart".

Is there an option to disable auto-negation?

If not, is there any objection to adding one?

path arrays not working for me?

{ file:[ require("path") ] }

and

app --file asdf1 --file asdf2

results in

{ file:"/path/to/asdf2" }

I only get an array if I do

{ file:Array }

Unknown option swallows a known one

Here's an example of everything working properly:

$ ./my-program.js --flag --foo hello
parsed =
{ flag: true,
  foo: 'hello',
  argv: 
   { remain: [],
     cooked: [ '--flag', '--foo', 'hello' ],
     original: [ '--flag', '--foo', 'hello' ],
     toString: [Function] } }

So far, so good. However, a mistaken name for the boolean option throws everything off, so if --myflag was mistakenly used instead of --flag, we get this:

$ ./my-program.js --myflag --foo hello
parsed =
{ myflag: '--foo',
  argv: 
   { remain: [ 'hello' ],
     cooked: [ '--myflag', '--foo', 'hello' ],
     original: [ '--myflag', '--foo', 'hello' ],
     toString: [Function] } }

Note how the mistyped 'myflag' option has now consumed the --foo option as its value, leaving what was intended as foo's value as part of 'remain'.

Since it can't be determined whether an unknown option is intended to have a value or not, and since nopt is designed to allow for the use of unknown options, it would make sense to check a possible value for an unknown option to see if it may, in fact, be the name of a known option. In the above example, this would mean that 'foo' would be correctly identified as an option name rather than being consumed as a value.

Default handling of multi value args

I'm wondering if nopt could default to treating multiple args for the same option as an Array type. For example, when passing:

$ node app.js --log warn --log err

nopt currently returns true for log, but a more sensible default would be ['warn', 'error'] since multiple values were passed. Thoughts?

nopt.js:210 TypeError: Cannot read property 'name' of null

Latest release has the following bug:

[email protected] install /Users/dseeto/code/node_modules/node-sass
> node scripts/install.js

/Users/dseeto/code/node_modules/nopt/lib/nopt.js:210
    if (t && ((type.name && t.type.name) ?
                   ^
TypeError: Cannot read property 'name' of null
    at validate (/Users/dseeto/code/node_modules/nopt/lib/nopt.js:210:20)
    at validate (/Users/dseeto/code/node_modules/nopt/lib/nopt.js:179:11)
    at /Users/dseeto/code/node_modules/nopt/lib/nopt.js:101:12
    at Array.map (native)
    at /Users/dseeto/code/node_modules/nopt/lib/nopt.js:67:15
    at Array.forEach (native)
    at Function.clean (/Users/dseeto/code/node_modules/nopt/lib/nopt.js:55:21)
    at /Users/dseeto/code/node_modules/npmconf/npmconf.js:411:10
    at Array.forEach (native)
    at validate (/Users/dseeto/code/node_modules/npmconf/npmconf.js:410:11)

unexpected arguments not parsed correctly?

I've noticed that nopt has changed the way it parses unexpected arguments from v1.0.x to v2.1.x. Now, this may be by design. If it is, please let me know and close the issue.

$ npm install nopt@~1.0.10
npm WARN package.json [email protected] No README.md file found!
npm http GET https://registry.npmjs.org/nopt
npm http 304 https://registry.npmjs.org/nopt
npm http GET https://registry.npmjs.org/abbrev
npm http 304 https://registry.npmjs.org/abbrev
[email protected] node_modules/nopt
└── [email protected]

$ node -pe "require('nopt')({}, {}, ['-r', '1.10'], 0).r"
1.1

$ node -pe "require('nopt')({}, {}, ['-r', 'v1.10'], 0).r"
v1.10

$ npm install nopt@latest
npm WARN package.json [email protected] No README.md file found!
npm http GET https://registry.npmjs.org/nopt
npm http 304 https://registry.npmjs.org/nopt
npm http GET https://registry.npmjs.org/abbrev
npm http 304 https://registry.npmjs.org/abbrev
[email protected] node_modules/nopt
└── [email protected]

$ node -pe "require('nopt')({}, {}, ['-r', '1.10'], 0).r"
true

$ node -pe "require('nopt')({}, {}, ['-r', 'v1.10'], 0).r"
true

This seems like:

  1. a regression in nopt (since it's now parsing unexpected arguments into booleans instead of numbers or strings)
  2. a bug in how nopt parses (or used to parse) numbers, since "1.10" was parsed into 1.1 and not left as a string.

See gruntjs/grunt#894 for more details.

Thanks!

[BUG] Unexpected arguments not parsed correctly?

I've noticed a behavior change from [email protected] -> [email protected] with the parsing of unexpected arguments.

  • In [email protected] '-a a' and '-a=a' (as well as with --) were equivalent.
  • In [email protected] '-a a' and '-a=a' (as well as with --) behave differently. Basically, -a a works like -a (setting prop a to true) but adds "a" the the remain array. Shouldn't both set prop a to string "a"?
$ npm install nopt@~1.0.10
npm WARN package.json [email protected] No README.md file found!
npm http GET https://registry.npmjs.org/nopt
npm http 304 https://registry.npmjs.org/nopt
npm http GET https://registry.npmjs.org/abbrev
npm http 304 https://registry.npmjs.org/abbrev
[email protected] node_modules/nopt
└── [email protected]

$ node -pe "require('nopt')({}, {}, ['-a', 'a', '-b=b', '--c', 'c', '--d=d'], 0)"
{ a: 'a',
  b: 'b',
  c: 'c',
  d: 'd',
  argv:
   { remain: [],
     cooked: [ '-a', 'a', '-b', 'b', '--c', 'c', '--d', 'd' ],
     original: [ '-a', 'a', '-b=b', '--c', 'c', '--d=d' ],
     toString: [Function] } }

$ npm install nopt@latest
npm WARN package.json [email protected] No README.md file found!
npm http GET https://registry.npmjs.org/nopt
npm http 304 https://registry.npmjs.org/nopt
npm http GET https://registry.npmjs.org/abbrev
npm http 304 https://registry.npmjs.org/abbrev
[email protected] node_modules/nopt
└── [email protected]

$ node -pe "require('nopt')({}, {}, ['-a', 'a', '-b=b', '--c', 'c', '--d=d'], 0)"
{ a: true,
  b: 'b',
  c: true,
  d: 'd',
  argv:
   { remain: [ 'a', 'c' ],
     cooked: [ '-a', 'a', '-b', 'b', '--c', 'c', '--d', 'd' ],
     original: [ '-a', 'a', '-b=b', '--c', 'c', '--d=d' ] } }

3.0.5 release failing to install on my build server

I'm still gathering details, but figured I'd go ahead and report it.

16:38:00 /usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:210
16:38:00     if (t && ((type.name && t.type.name) ?
16:38:00                    ^
16:38:00 TypeError: Cannot read property 'name' of null
16:38:00     at validate (/usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:210:20)
16:38:00     at validate (/usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:179:11)
16:38:00     at /usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:101:12
16:38:00     at Array.map (native)
16:38:00     at /usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:67:15
16:38:00     at Array.forEach (native)
16:38:00     at Function.clean (/usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:55:21)
16:38:00     at /usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/npmconf.js:411:10
16:38:00     at Array.forEach (native)
16:38:00     at validate (/usr/local/jenkins/workspace/ultra-learn-ultra-ui_develop-ui-test/node_modules/grunt-sass/node_modules/node-sass/node_modules/npmconf/npmconf.js:410:11)

Is there any way to disable Abbreviations?

It seems like abbrev is hardcoded into nopt. Is it possible to provide a configuration to disable it? We already have the short options, not really sure why we still need abbrevs.

Arguments parsed to numbers incorrectly.

I know this is going to be a little bit subjective, but perhaps you can help.

It's hard to pass a version number to nopt like -r=1.10 because it will treat that value as the number 1.1 and not the string "1.10". This can be worked around by prefixing it like -r=v1.10 but it's inconvenient to have to strip out the leading v in that case if you don't need it.

Would it be possible for nopt to check to see if the value, once converted to a number and then back to a string matches the original string, Eg.

function getNumberOrString(str) {
  var num = Number(str);
  // Only return number if a) it's a valid number, and b) when coerced
  // back to a string, that string is the same as the original string.
  return !isNaN(num) && String(num) === str ? num : str;
}

getNumberOrString("1.23") // 1.23
getNumberOrString("1.10") // "1.10"
getNumberOrString("01234") // "01234"

What nopt currently does is something more like this:

function getNumberOrString(str) {
  var num = Number(str);
  // Only return number if it's a valid number.
  return !isNaN(num) ? num : str;
}

getNumberOrString("1.23") // 1.23
getNumberOrString("1.10") // 1.1
getNumberOrString("01234") // 1234

Here's an example of this "bug" in action:

$ npm install nopt@latest
npm WARN package.json [email protected] No README.md file found!
npm http GET https://registry.npmjs.org/nopt
npm http 304 https://registry.npmjs.org/nopt
npm http GET https://registry.npmjs.org/abbrev
npm http 304 https://registry.npmjs.org/abbrev
[email protected] node_modules/nopt
└── [email protected]

$ node -pe "require('nopt')({}, {}, ['-a=1.23', '-b=1.10', '-c=01234'], 0)"
{ a: 1.23,
  b: 1.1,
  c: 1234,
  argv:
   { remain: [],
     cooked: [ '-a', '1.23', '-b', '1.10', '-c', '01234' ],
     original: [ '-a=1.23', '-b=1.10', '-c=01234' ] } }

[BUG] Parsing issues for options within a string on 4.0.x+

Original issue: ember-cli/ember-cli#6970
Parsing options issues for a string with "options"
node test.js foo bar --options '--split 2 --random'

Issue after: 651d447.
https://regex101.com/r/aoa7GZ/1

Example test.js:

var nopt = require("nopt")
var knownOpts = { options: String };
var parsed = nopt( knownOpts, {}, process.argv, 0)
console.log("parsed: ", parsed);
console.log("parsed.options: ", parsed.options);

3.0.x

node test.js foo bar --options '--split 2 --random'

parsed:  { options: '--split 2 --random',
  argv: 
   { remain: [],
     cooked: [ '--options', '--split 2 --random' ],
     original: [ '--options', '--split 2 --random' ] } }

parsed.options: --split 2 --random

4.0.X:

node test.js foo bar --options '--split 2 --random'

parsed:  { options: '',
  'split 2 --random': true,
  argv: 
   { remain: [],
     cooked: [ '--options', '--split 2 --random' ],
     original: [ '--options', '--split 2 --random' ] } }

parsed.options:

Unexpected string parsing

Hello!

I have knownOptions set to: { config: String }.

Then I run my program like this: ./test --config I have in output { config: 'true', argv: { ... } } that seems a bit strange, because I expected config field set to empty string.

Is it a bug or maybe such behaviour is by design?

Descriptions and --help?

Feature request:

Descriptions for my arguments so when I do "myapp --help" it will print out a nice description.

The many2 : [path] example does not seem to work

Using [email protected] and [email protected] and given the following source 'command'

#!/usr/bin/env /usr/bin/node
var path = require('path');
var nopt = require('nopt');
var parsed = nopt({
    's': [path]
});
console.log(parsed);

By making this executable, I then invoke it by

./command -s /tmp -s /bin -s /var

The output will be

{ s: '/var',
  argv: 
   { remain: [],
     cooked: [ '-s', '/tmp', '-s', '/bin', '-s', '/var' ],
     original: [ '-s', '/tmp', '-s', '/bin', '-s', '/var' ] } }

I would have expected the following, though

{ s: ['/tmp', '/bin', '/var'],
  argv: 
   { remain: [],
     cooked: [ '-s', '/tmp', '-s', '/bin', '-s', '/var' ],
     original: [ '-s', '/tmp', '-s', '/bin', '-s', '/var' ] } }

Am I doing something wrong here?

--foo doesn't work

I followed your example in the Readme but myapp --foo "hello" didn't work.

It's showing blank lines when I press enter.

Type objects not ===

I have this weird issue where Wrapper Objects do not equate with each other. I'm running babel, and I believe that it is overriding what is normally a Number, such that the template being passed in and the internal typeDefs do not match any more.

I can fix this by changing the line here to

if (t && ((type.name && t.type.name) ? (type.name === t.type.name) : (type === t.type))) {

This works, because the object types have a name describing them, which is a string which does a true equality test, and defaults to the old behaviour if this doesn't exist.

The validation doesn't rely on them being the same object - is this a valid thing to do?

Odd behavior with wrong keys

I have the following case:
long args are
--account / -a
--credentials / -c
--options / -o

now If I pass "--acount bla" (typod) it does not report a unknown key but interprets it as:

"--account --credentials --options bla" which is entirely wrong

[QUESTION] null values are objects?

When having this code:

// my-program.js
var output = nopt({
        val: [Number, null]
    }, {}, process.argv, 2);

then attempting this cli command:

$ node my-program.js

gives me:

var output = { "val" : null};

Which is okay. However, I dont think the following should happen, should it?:

output.val === null  // => false

[QUESTION] Handling default values?

I'm wondering what is the expected way to handle arguments or options that are not supplied.

To give one example, I have an option which should be true by default:

const knownOpts = {headers: [Boolean]};

And this would be commonly used in the cmd line as --no-headers. In the current scheme I will either have:

parsed.headers = undefined // falsy, but want it to be true
or
parsed.headers = false // definitely falsy

At the moment it feels like nopt creates an incomplete model of my options and I then have to pass to another function to normalise all incomplete values. Perhaps this is either a feature request or out of scope.

Short option parsing error

If you use a set of short options as a single shell word, nopt will first try to find a long option name that completes the word instead of checking your short options match:

var nopt = require('nopt')

var options = { clear:  Boolean,
                config: Boolean,
                length: Number
              }

var shorts  = { c: 'config', l: 'length' }

nopt(options, shorts, ['node', 'bin/foo', '-cl', '6'])
// -> { clear: true }

I was expecting this to return { config: true, length: 6 }.

It's a good job I made my --clear command prompt for confirmation, or I'd have lost a bunch of data ;)

usage statement

Would be nice to have something that prints the usage statement nicely for you. Maybe even allow descriptions to be passed to the option definitions for this. Without a usage statement, most program options cannot be discovered and providing a common way to print a usage statement is nice since completion tools can be built around it.

[BUG] no typeDef for Array

I can't validate type [String,Array]

It should work with validate(), but that function is not exposed.

Glob patterns return unexpected results

I'm trying to allow the use of glob patterns but I'm having trouble getting it to work.

var options = require('nopt')({
  file: String,
}, {
  'f': '--file',
}, process.argv, 2);

index.js --file www/*.js

options.file returns the first file in the directory as a string even if there are multiple files. And since it's returning a file and not the original string I can't manually glob the pattern. I've tried file: [require('path')] but that just resolved first path it finds.

Is there a way to turn off the path coercion or have nopt correctly recognize glob patterns and return an array of paths?

Get raw user input

app --path folder/file.ext

I'd like to get that raw path value for use in error messages because the resolved path is not only too long to read, it's not what the user typed (communication, blah blah). So far, I'm using argv.cooked, but it seems redundant because nopt already performs/performed this logic (option type, etc). Is there a better way to do this, possibly using something in nopt?

license clarification

Please clarify that you intent on making this code available under the MIT Open Source license. I assume that you are, but I'd rather not assume, and see the license explicitly . Thanks! Gil

[QUESTION] Why does nopt only work with cli args?

It makes sense to me that if you have a package that takes an options = {...} object as a parameter, you'd want the same level of validation and error handeling than the one you'd have on CLI args.

[BUG] nopt breaks on arguments passed in as numbers

Please consider this minimal example:

node << _EOT_
var nopt   = require("nopt")
,   parsed = nopt( {}, {}, [ 123 ], 0 )
;
_EOT_

Output:

... /node_modules/nopt/lib/nopt.js:239
    if (arg.match(/^-{2,}$/)) {
            ^
TypeError: Object 123 has no method 'match'
    at parse ( ... /node_modules/nopt/lib/nopt.js:239:13)
    at nopt ( ... /node_modules/nopt/lib/nopt.js:40:3)

Contrived as this may seem, in the wild I found that yeoman-generator actually does this.

[BUG] --no-[parameterName] doesn't allow setting to null for some typeDefs

The purpose of "--no-myParam" is to allow setting a parameter to null instead of undefined, because "-myParam null" would set it to the string value 'null' instead of the javascript value null.

However, this feature is buggy for some typeDefs.

if typeDef is String
"--no-myParam" the parse() function sets it to false instead of null
However, clean() internally calls validateString() which changes it to 'false'

so, "--no-myParam" has no purpose in the case of typeDef String because i could have used "-myParam false" instead.

I haven't tested to see if the other typeDefs have similar issues, but it's possible.

[DOCS] Read-me description inconsistent with actual handling of invalid option values

As of v3.0.1, README.md states:

By default, nopt outputs a warning to standard error when invalid options are found.

Note that 'invalid option' refers to an invalid value specified for a known option in this context. I've submitted a PR to clarify this.

In practice, no such warning is printed. Nothing in nopt.js suggests that even an attempt is made to do so.
As an aside, there's a remove variable that doesn't seem to do anything.

Not sure what the actual intent is, but it looks like the warning was intentionally removed and that the read-me needs to be updated accordingly, including removing the following passage, which becomes moot:

If no nopt.invalidHandler is assigned, then it will console.error its whining. If it is assigned to boolean false then the warning is suppressed.

undefined value on line 210

I am the following error when I try to install a program that has nopt as a dependency:

    if (t && ((type.name && t.type.name) ?
                   ^
TypeError: Cannot read property 'name' of null
    at validate (/Users/davidhasenjaeger/Wirestorm/projects/costco-member-scheduling/client/node_modules/node-sass/node_modules/npmconf/node_modules/nopt/lib/nopt.js:210:20)

Rickrolled

I've been rickrolled by a node module.

How to have an option with-a-dash in the name?

I was using the following code and I could have swore that it was working, but it does not seem to be working today. args["no-restart"] and args["init-default"] are always undefined even when they exist in process.argv as '--init-default' and '--no-restart'.

Is this supported and if not, is there any reason that it should not be?

exports.known = {
  help: Boolean, 
  "init-default": Boolean,
  "no-restart": Boolean,
  verbose: Boolean,
  version: Boolean,
  path: path
};

exports.aliases = {
  h: '--help', 
  v: '--version',
  V: '--verbose'
};

var args = nopt(exports.known, exports.aliases, process.argv, 2);
var remain = args.argv.remain;
if (remain && remain.length > 0) {
  args.path = remain[0];
}

args.initDefault = args["init-default"];
args.noRestart = args["no-restart"];
// ...

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.