Giter VIP home page Giter VIP logo

args's Introduction

args

Build Status XO code style

This package makes creating command line interfaces a breeze.

Features

  • Git-style sub commands (e.g. pizza cheese executes the "pizza-cheese" binary)
  • Auto-generated usage information
  • Determines type of option by checking type of default value (e.g. ['hi'] => <list>)
  • Clean syntax for defining options and commands
  • Easily retrieve values of options
  • Automatically suggests a similar option, if the user entered an unknown one

Usage

Install the package (you'll need at least version 6.0.0 of Node):

npm install --save args

Once you're done, you can start using it within your binaries:

#!/usr/bin/env node

const args = require('args')

args
  .option('port', 'The port on which the app will be running', 3000)
  .option('reload', 'Enable/disable livereloading')
  .command('serve', 'Serve your static site', ['s'])

const flags = args.parse(process.argv)

The upper code defines two options called "port" and "reload" for the current binary, as well as a new sub command named "serve". So if you want to check for the value of the "port" option, just do this:

// This also works with "flags.p", because the short name of the "port" option is "p"

if (flags.port) {
  console.log(`I'll be running on port ${flags.port}`)
}

In turn, this is how the auto-generated usage information will look like:


  Usage: haha [options] [command]


  Commands:

    serve, s       Serve your static site
    help           Display help

  Options:

    -v, --version  Output the version number
    -r, --reload   Enable/disable livereloading
    -h, --help     Output usage information
    -p, --port     The port on which the app will be running

API

.option(name, description, default, init)

Register a new option for the binary in which it's being called.

  • name: Takes a string which defines the name of the option. In this case, the first letter will be used as the short version (port => -p, --port). However, it can also be an array in which the first value defines the short version (p => -p) and the second one the long version (packages => --packages).
  • description: A short explanation of what the option shall be used for. Will be outputted along with help.
  • default: If it's defined, args will not only use it as a default value for the property, but it will also determine the type and append it to the usage info when the help gets outputted. For example: If the default param of an option named "package" contains an array, the usage information will look like this: -p, --package <list>.
  • init: A function through which the option's value will be passed when used. The first paramater within said function will contain the option's value. If the parameter "default" is defined, args will provide a default initializer depending on the type of its value. For example: If "default" contains an integer, "init" will be parseInt.

.options(list)

Takes in an array of objects that are each defining an option that shall be registered. This is basically a minimalistic way to register a huge list of options at once. Here's what each option object needs to look like:

{
  name: 'port',
  description: 'The port on which the app runs',
  init: content => content,
  defaultValue: 3000
}

However, the keys init and defaultValue are not strictly required.

.command(name, description, init, aliases)

Register a new sub command. Args requires all binaries to be defined in the style of git's. That means each sub command should be a separate binary called "<parent-command>-<sub-command>".

For example: If your main binary is called "muffin", the binary of the subcommand "muffin list" should be called "muffin-list". And all of them should be defined as such in your package.json.

  • name: Takes a string which defines the name of the command. This value will be used when outputting the help.

  • description: A short explanation of what the command shall be used for. Will be outputted along with help.

  • init: If a function was passed through at this parameter, args will call it instead of running the binary related to that command. The function receives three arguments:

    function aCommand (name, sub, options) {
      name // The name of the command
      sub // The output of .sub
      options // An object containing the options that have been used
    }

    Using an initializer is currently only recommended if your command doesn't need special/different options than the binary in which you're defining it. The reason for this is that the "options" argument of the upper function will contain the options registered within the current binary.

  • aliases: Takes in an array of aliases which can be used to run the command.

.example(usage, description)

Register an example which will be shown when calling help

  • usage: Takes a string which defines your usage example command
  • description: A short explanation of what the example shall be used for. Will be outputted along with help.

.examples(list)

Takes in an array of objects that are each defining an example that shall be registered. This is basically a minimalistic way to register a huge list of examples at once. Here's what each option object needs to look like:

{
  usage: 'args command -d',
  description: 'Run the args command with the option -d'
}

.parse(argv, options)

This method takes the process' command line arguments (command and options) and uses the internal methods to get their values and assign them to the current instance of args. It needs to be run after all of the .option and .command calls. If you run it before them, the method calls after it won't take effect.

The methods also returns all options that have been used and their respective values.

  • argv: Should be the process' argv: process.argv, for example.
  • options: This parameter accepts an object containing several configuration options.

.sub

This property exposes all sub arguments that have been parsed by mri. This is useful when trying to get the value after the command, for example:

pizza ./directory

The upper path can now be loaded by doing:

// Contains "./directory"
const path = args.sub[0]

This also works completely fine with sub commands: After you've registered a new command using .command(), you can easily check the following sub argument within its binary like mentioned above:

pizza eat ./directory

.showHelp()

Outputs the usage information based on the options and comments you've registered so far and exits, if configured to do so.

.showVersion()

Outputs the version and exits, if configured to do so.

Configuration

By default, the module already registers some default options and commands (e.g. "version" and "help"). These things have been implemented to make creating CLIs easier for beginners. However, they can also be disabled by taking advantage of the following properties:

Property Description Default value Type
exit Automatically exits when help or version is rendered { help: true, version: true } Object
help Automatically render the usage information when running help, -h or --help true Boolean
name The name of your program to display in help Name of script file String
version Outputs the version tag of your package.json true Boolean
usageFilter Allows you to specify a filter through which the usage information will be passed before it gets outputted null Function
 value Suffix for the "Usage" section of the usage information (example) null  String
mri Additional parsing options to pass to mri, see mri docs for details undefined Object
mainColor Specify the main color for the output when running the help command. See chalk docs for available colors / modifiers. You can specify multiple colors / modifiers with an array. For example: {mainColor: ['red', 'bold', 'underline']} yellow String[Array]
subColor Specify the sub color for the output when running the help command. See chalk docs for available colors / modifiers. You can specify multiple colors / modifiers with an array. For example: {subColor: ['dim', 'blue']} dim String[Array]

You can pass the configuration object as the second paramater of .parse().

Contribute

  1. Fork this repository to your own GitHub account and then clone it to your local device
  2. Link the package to the global module directory: npm link
  3. Within the module you want to test your local development instance of args, just link it to the dependencies: npm link args. Instead of the default one from npm, node will now use your clone of args!

As always, you can run the AVA and ESLint tests using: npm test

Special thanks

... to Dmitry Smolin who donated the package name. If you're looking for the old content (before I've added my stuff) of the package, you can find it here.

Authors

args's People

Contributors

aapokiiso avatar chabou avatar codyzu avatar danielruf avatar dotob avatar greenkeeper[bot] avatar greenkeeperio-bot avatar icebob avatar julianduque avatar keineausweise avatar leo avatar markhalliwell avatar matheuss avatar mspiess avatar ntwcklng avatar oskarrough avatar pablopunk avatar rtsao avatar tootallnate avatar yuler 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

args's Issues

An option starting with 'h' causes confusing help output

My app has a config option called 'host'. When you run the program with "-h", the help is printed, which is not unexpected.

However, the following output is

const args = require('args')
  .option('interval', 'How often (in seconds) to ping the device', 30, s => 1000 * s)
  .option('delay', 'How long (in seconds) the device must be gone before reporting no presence', 15 * 60, s => 1000 * s)
  .parse(process.argv)

Note that there are two '-h' options.

Expose .renderHelp()

People should be able to show the help whenever they want to. Maybe rename to .showHelp()

Return properties from .parse()

Some people don't like magic globals. So we should allow this (but still keep magic properties):

const properties = args.parse(process.argv)

Allow options with no short versions

Hi,

If there is already a short version with a given letter, I think next options starting with same letter should not expose a short version at all.

Here I'm trying to create a list PR and my --cors options conflits with the --cache option:

    -c, --cache <n>    How long static files should be cached in the browser (seconds)
    -c, --cors <list>  Setup * CORS headers to allow requests from any origin

As far as I understand, I can't setup no short version at all or a short version of more than 1 letter. It means there can't be more than 26 options available and I have to pick a random letter for my cors options

Make --version readonly

Currently, it looks like this (we need to remove [value]):

-v, --version [value]  Output the version number

Drop `-h` and only leave `help`

-h is pretty cryptic and doesn't help newbs. Also having two ways for outputting the usage information is just confusing to everyone!

Ability to add information to the 'Usage' field

I really like this package and was wondering if you were planning on adding the ability to add information to the 'Usage' field?

For example:

Usage: haha [options] [command] <directory>

Config as an API-Method

I think this syntax is more readable and easier to understand:

args
  .option('a', 'abc')
  .command('b', 'def')
  .config({name: 'abcdef'})

args.parse(process.argv)

What do you think?

Allow `false` default value

Would a pull request be accepted that allows an argument to be false by default? Is there any way of doing this already?

This would be useful for implementing a command line switch to enable a specific function that is disabled by default.

An application with no commands shows [commands] usage

My application accepts no commands, but has options. The setup looks like this

const args = require('args')
  .option('interval', 'How often (in seconds) to ping the device', 30, s => 1000 * s)
  .option('delay', 'How long (in seconds) the device must be gone before reporting no presence', 15 * 60, s => 1000 * s)
  .parse(process.argv)

However, when I run the app with --help, the output looks like this

[chris:~/device-presence] master(+6/-1) ± node index.js --help

  Usage: index.js [options] [command]

  Commands:

    help  Display help

  Options:

    -d, --delay <n>     How long (in seconds) the device must be gone before reporting no presence
    -h, --help          Output usage information
    -i, --interval <n>  How often (in seconds) to ping the device
    -v, --version       Output the version number

Since my application does not use commands, it would be nice if the usage section did not imply that it did.

Incorrect results when passing command line argument with default from process.env

This is a weird one. When passing a value to an argument via the command line, while also defining a fallback on process.env, [object Object] is returned instead of the correct value.

I took these steps to reproduce the issue:

  1. In a new directory do npm install args
  2. Create a file fail.js with these contents:
const args = require('args');
args.option(['p', 'port'], 'The port to run on', process.env.PORT || 3000);
const config = args.parse(process.argv);
console.log(`Your port is: ${config.port}`);
  1. Run the following tests on the CLI and observe the weird results:
$ node fail.js
Your port is: 3000 # all good

$ node fail.js -p 1000
Your port is: 1000 # all good

$ PORT=1000 node fail.js
Your port is: 1000 # all good

$ PORT=1000 node fail.js -p 1001
Your port is: [object Object] # failure

Note if I take out process.env in that script and instead specify a single default value of 3000 with no fallback everything works as expected.

Happy to look into resolving the issue if you don't have time to, as it's currently causing bugs in the master branch of slackin here: rauchg/slackin#206

A given value of an option is erased by the default value

The script program defines its option like this:

args.option('parameters', "Your parameters", []);
const flags = args.parse(process.argv);
console.log(flags);

A test in a terminal returns an empty array:

program command --parameters 10 20

Subcommands doesn't work on windows

The subcommand binary isn't found on windows environments

C:\> tool config get option
C:\Users\jduque\AppData\Roaming\npm\node_modules\tool\node_modules\args\index.js:342
throw err
^

Error: spawn tool.js-config ENOENT

Add ability to specify a default subcommand

Just like now running now deploy by default, we could add the ability to specify a default subcommand.
Maybe like this:
.defaultCommand('deploy', 'Deploy') or
.command('deploy', 'Deploy', { defaultCommand: true }
or via the options in .parse(process.argv, { defaultCommand: 'deploy' }

args.option vs args.options, bug?

Hi!

So I have this simple script

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

var availableTypes = [
  'all',
  'products',
  'conversion-chart'
];

args.option('type', 'The type of index to update ('+ availableTypes.join(', ') +')');
/*
args.options([
  { name: 'type', description: 'The type of index to update ('+ availableTypes.join(', ') +')' }
]);
*/

args.examples([
  { usage: path.basename(__filename) + ' update --type all', description: 'Update all search indexes.' },
  { usage: path.basename(__filename) + ' update --type products --type conversion-chart', description: 'Update only 2 specific search indexes.' }
]);

var flags = args.parse(process.argv, {
  name: path.basename(__filename),
  version: false
});

console.log(flags);

When I call the script scripts.js -t all

I get this

{ t: 'all', type: 'all' }

Now if I comment the args.option and uncomment args.options and run it again, I get this :

{ t: false, type: false }

shouldn't that give the same results or am I missing something?

Support for evaluating without exiting

Hi 👋 Thanks for a great args parser.

What do you think of the possibility to send in an option that will stop the process.exit() from the help generation? It can be useful in systems that has plugins which themselves has options. The snippet below shows an example use case:

const {adapter} = args
  .option(['a', 'adapter'], 'The adapter used')
  .parse(argv, { help: false, exit: false })

const options = args
  .option(['a', 'adapter'], 'The adapter used')
  .options(adapter.options)
  .parse(argv, { name: `some-cli (with adapter "${adapter}")`)

I am happy to implement it if you think it would be an valuable to the library.

Add ability to change colors

For example .colors({mainColor: 'red', subColor: 'bold' }) would output the commands and options in red, and the description in chalk.bold instead of chalk.dim

ENOENT error for spawning child processes

Hey @leo,
This fix might not be necessary, but when I created my first args subcommand I got:

Error: spawn gest-test ENOENT
    at exports._errnoException (util.js:1028:11)
    at Process.ChildProcess._handle.onexit (internal/child_process.js:193:32)
    at onErrorNT (internal/child_process.js:359:16)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)
    ...

and addingpath.join(__dirname, this.binary + '-' + (Array.isArray(details.usage) ? details.usage[0] : details.usage)) was my quick fix, but this only fixed the problem if I named my binary gest-test, not gest-test.js. A better solution would be to only spawn the file mapped to by package.json's bin, or maybe default to .js.

I can tackle this, but I would like to know which approach you think is best.
-- @mfix22

Process.exit() in help

The showHelp will not console.log bigger helps due to the process.exit(). I think using process.exitCode or no exit at all would be better, and let the users to handle their exit on help.

thanks

Subcommand options broken in v2.6

Hi! The new behavior of detecting unknown options is broken for subcommands. E.g.

$ foo bar -o=baz
The option "o" is unknown. Here's a list of all available options:
[etc]

In v2.4 (which I upgraded from) it works fine.

Automatically show help only for options, not sub commands

@ntwcklng We kinda forgot that people need to be able to specify an unknown sub command, as a path to a directory or similar:

serve directory
micro directory

Both of these would throw the help, because the "sub command" is unknown.

Of course we could just add the ability to deactivate this using a config parameter, but since these are like 90% of the cases, I would rather only use it for options, not sub commands. 😊 🙏

Drop magic global

The only way to get to the values of the options shall be .parse(). For example, the current way of doing it makes option names conflict with existing methods of the module.

Clean up .raw._

Since this property comes directly from minimist, we need to remove the paths of the binaries.

cannot name an option "version"

I want to specify a string option named "--version" but because of the default version option, it will not let me override it (as far as I can tell). I can submit a patch if this isn't supported.

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.