Coder Social home page Coder Social logo

mattallty / caporal.js Goto Github PK

View Code? Open in Web Editor NEW
3.4K 37.0 96.0 4.19 MB

A full-featured framework for building command line applications (cli) with node.js

License: MIT License

JavaScript 2.91% Shell 0.47% TypeScript 96.61%
cli cli-app nodejs node node-js command-line-parser command-line argument-parser terminal argument-parsing

caporal.js's People

Contributors

bbusschots avatar bertho-zero avatar budnix avatar bwinterton avatar chriscalo avatar danielruf avatar dependabot[bot] avatar donmccurdy avatar drewsonne avatar fabiospampinato avatar fgarcia avatar gcox avatar ihorskyi avatar ilyar avatar jhorbulyk avatar jorgebucaran avatar khaosdoctor avatar kinok avatar kobleistvan avatar limichange avatar lmammino avatar masnagam avatar mattallty avatar mfilenko avatar mycaule avatar prayagverma avatar robertrossmann avatar semantic-release-bot avatar szpadel avatar thecodejunkie 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

caporal.js's Issues

The typescript types are wrong with the latest version of Typescript

Failing program:

import * as program from 'caporal'
program.version('0.1.0').name('yarn run make')

Property version does not exist on type 'typeof 'caporal''

Type-casting to any and it works.

Successful program (when it shouldn't be):

import program from 'caporal'
program.version('0.1.0').name('yarn run make')

The compiled code fails with TypeError: Cannot read property 'version' of undefined

Enter negative number as Argument

I'm trying to get data from user by console to solve quadratic. It run successfully even when I entered 3 float numbers.
But when I enter Negative number it does not work, eg:
node caporalDemo.js solve 7 8 -2
it say
Error: Wrong number of argument(s) for command solve. Got 2, expected exactly 3.
My caporalDemo.js --help :
caporalDemo.js 1.0.0

USAGE

 caporalDemo.js solve <a> <b> <c>

ARGUMENTS

 <a>      Value of a      required      
 <b>      Value of b      required      
 <c>      Value of c      required       `

So How can I input Negative arguments ?

Options without parameters ("flags")

Is it possible to define flag-like options that take zero parameters, e.g. --verbose? It seems that value following the option gets always assigned as option value and I haven't found a way around this behaviour.

Error: Unknown option --color.

When using the --no-color flag, I get colorless output, but I also get this error:

Error: Unknown option --color.
Type stacker --help for help.

Adding a default command removes all commands from auto-generated help

Hi,
After updating to Caporal 0.5.0, the commands in my help are missing.

If I remove the default command, by removing .action from the below snippet, all the commands appear again in help:

prog
  // default command
  .version(VERSION)
  .action(commands.nextUndoneAction)
  .description(COMMAND_DESCRIPTIONS.default)

I'm talking about Moro, and here's the link to that part of code: link to repo

What I expect?
All the commands appear in help
What I get?
No help for specific commands is listed in help.

Might be related to #47 and #44

Colorize's regexes are too restrictive

Something like this doesn't get properly colorized:

prog.option ( '--config <path|object>', '' );

Because | is not included in the allowed characters matched by the regex, for no apparent reason.

Setup app name

Great package ๐Ÿ‘

How we can change the app name ? By default, it seem to be the filename.

It will be nice if we can do :

prog('PizzaHut')
 .version('1.0.0')

or

prog
 .pkg('PizzaHut')
 .version('1.0.0')

Edit :

Solved. Caporal export an object (Program) with some Getter and Setter extended.

We can setup "name", "description" and "version" like that : ๐Ÿฅ‡

prog
  .name('PizzaHut')
  .bin('pizza.js')
  .description('The PizzaHut CLI')
  .version('1.0.0')

Bug with logger in async functions

The built-in logger does not work in asynchronous functions, but console.log does.

The following very simple app demonstrates the problem clearly:

#!/usr/bin/env node
const cli = require('caporal');

cli.version('0.0.1');
cli.command('console', 'A Test Command using console').action(testConsole);
cli.command('logger', 'A Test Command using logger').action(testLogger);

cli.parse(process.argv);

async function testConsole(args, opts, logger){
    console.log('boo!');
    let p = await Promise.resolve(true);
    console.log('hiss!');
    return p;
}

async function testLogger(args, opts, logger){
    logger.log('boo!');
    let p = await Promise.resolve(true);
    logger.log('hiss!');
    return p;
}

Here's what happens when I run it with the latest Caporal on the latest nodeJS:

bart-iMac2013:vtemp bart$ node --version
v8.2.1
bart-iMac2013:vtemp bart$ ./index.js console
boo!
hiss!
bart-iMac2013:vtemp bart$ ./index.js logger
bart-iMac2013:vtemp bart$ 

Accept dot notation

Would you consider adding dot notation support? (See yargs example).

It would works as follow:

myprog --user.name Batman
// options = {user: {name: 'Batman'}}

Currently it's possible to defined the option user.name and then parse it later. But that forces us to define of the possible "suboption" otherwise we get Error: Unknown option --user.name.
In many cases this time of notation is used to generate and options passed to a third-party module for which the possible options are not necessarily know or can numerous. Therefore it's not always possible or a good idea to list all the potential suboption and print them in the help.

Maybe we could allow to do something like this:

prog
  .option('--user <user>', 'User options', prog.DOT)

The help would look like this:

OPTIONS
   --user <user>                    User options

Optionally the user could use a custom transform in place of prog.DOT that would validate which suboption are allowed.

If all that is too complex or out of scope maybe we could just add an option to not return the Error: Unknown option --user.name. when the option user has been defined. Basically if user option is defined with some sort of "accept dot notation" flag, then accept any user.* options. And it would be up to the user to transform/validate in the action.

Custom logger could affect the auto-generated help

background

I'm using the logdown module as my custom logger, which is one of winston-compatible loggers. This module provides a functionality to attach a tiny emoji and a custom prefix to every messages like below.

const logger = require('logdown')('caporal:');
logger.info('this is a test message');
โ„น caporal: this is a test message

problem

The problem is the custom logger attaches the meta data(i.e., emoji and prefix) into the help instructions as well. This is because the help.js utilizes program.logger object to print out the help instructions. So, when I set my custom logger, the help instructions are like below.

โ„น caporal: 
   caporal test 1.0.0 
     
   USAGE

solution idea

The logdown logger may be not the only one that has this problem. I think the help instruction message should be independent with custom logger because it's auto-generated by Caporal.js. How about just using the default console.log function to print out the help instructions?

Please let me know there is any point that I misunderstood or missed ๐Ÿ‘

Default command

Hey, is it possible to add a default command? I did not find this mentioned on the documentation.

Completions for arguments not working

I am using corporal for the npm module "z1". It is a module that allows you to easily cluster node-apps.

In my code I am using caporal like this:

selection_046

This is my completion function:

selection_047

In this example case it returns a promise that resolves to the following array:

['exampleApp:/home/jonathan/Desktop/z1/example']

Now I am trying to use the completion:

selection_044

<tab> <tab>

selection_043

The completion for the [appName] argument is not showing up.
I am selecting one of the two options.

<tab> <tab>

selection_049

The completion for the [appName] is showing up (last in the list) where it should not.

I am not sure, if I am doing something wrong and it would be nice if you could help me out.
(Here is the complete CLI file https://github.com/robojones/z1/blob/caporal/cli/index.js)

Usage information not being autogenerated on a command level

The help command/opt seems to only be outputting high-level program usage information, i.e list of commands and required input.

Caporal automatically generates help/usage instructions for you. Help can be displayed using -h or --help options, or with the default help command.

Makes sense for the framework to also support usage information on the command level.

pizza order -h

In this example, the help usage should show any required arguments for this command as well as the options and their descriptions.

Recording of Issue

asciicast

Reasoning behind Caporal

It would be great to see documentation on why this was developed and how it differs from existing libraries such as yargs.

Postinstall issue with caporal in Windows, Node 8, x64 only

We have this project that needs to work across platforms and architecture, so we make sure to test them all out. For some reason Caporal fairly consistently fails on the postinstall step, but only on X64 windows and windows 8. Here's the error output, coming from appveyor:

> [email protected] postinstall C:\projects\pact-node\node_modules\caporal
> (test -f ./node_modules/husky/bin/install.js && node ./node_modules/husky/bin/install.js) || exit 0
npm ERR! path C:\projects\pact-node\node_modules\fsevents\node_modules
npm ERR! code EPERM
npm ERR! errno -4048
npm ERR! syscall scandir
npm ERR! Error: EPERM: operation not permitted, scandir 'C:\projects\pact-node\node_modules\fsevents\node_modules'
npm ERR!  { Error: EPERM: operation not permitted, scandir 'C:\projects\pact-node\node_modules\fsevents\node_modules'
npm ERR!   stack: 'Error: EPERM: operation not permitted, scandir \'C:\\projects\\pact-node\\node_modules\\fsevents\\node_modules\'',
npm ERR!   errno: -4048,
npm ERR!   code: 'EPERM',
npm ERR!   syscall: 'scandir',
npm ERR!   path: 'C:\\projects\\pact-node\\node_modules\\fsevents\\node_modules' }
npm ERR! 
npm ERR! Please try running this command again as root/Administrator.
npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\appveyor\AppData\Roaming\npm-cache\_logs\2017-11-10T00_07_01_211Z-debug.log
Command exited with code -4048

It would be great if this could be fixed as it's failing our CI builds. Thanks.

Way to specify that --blah "options" are always required as opposed to only required when the flag is passed

Maybe I'm missing something in the docs, but seems like [] and <> have slightly different semantics when specified in named options vs. in positional arguments. For options, the angle brackets appear to mean an option value is required whenever its associated flag is passed, whereas in positional arguments they indicate the given argument is always required. What I'd like to be able to do is always require that an option to be passed, in the example below for example i'd like a way to always require "stage" for example, yet it is treated

-s, --stage <stage>      Target environment [dev, staging, prod]      optional      
-a, --apps <apps>        Apps to deploy (comma separated list)        optional   

-s, --stage [stage]      Target environment [dev, staging, prod]      optional      
-a, --apps <apps>        Apps to deploy (comma separated list)        optional    

perhaps something like the following?

-s --stage {stage}     Target environment [dev, staging, prod]      required

Default help won't exit automatically

Hello,
Thanks for the nice project!

I'm using Caporal for an open source project. Currently, I got a problem: when the app is run by --help
the help screen won't stop, until I press ctrl x

Any ideas?

Custom Validator Errors are not logged

I notice that if I write a custom function validator, any errors thrown by my validator are not logged. Instead I just get a generic error like:

Error: Invalid value 'bar' for option --foo

This is a bummer, because I would like to notify the user as to why their argument/option is invalid.

For example, I wrote a DateValidator, to allow the users to pass in dates to my command:

function DateValidator(opt) {
	const date = new Date(opt);

	if (date.toString() === 'Invalid Date') {
		throw new Error(`"${opt}" is not a valid date. Option value must be an ISO date string or a timestamp in milliseconds`);
	}

	return date;
}

I would really like to be able to show that validation error to the user, so they don't have to guess as to why their command failed. For example:

Error: Invalid value 'today' for option --start-time
  "today" is not a valid date. Option value must be an ISO date string or a timestamp in milliseconds

To work around this, I overwrote the fatalError method of Caporal:

const prog = require('caporal');
const fatalErrorOrig = prog.fatalError.bind(cli);
prog.fatalError = (err) => {
	while (err.meta && err.meta.originalError) {
		err = err.meta.originalError;
	}

	fatalErrorOrig(err);
};

This, of course, is not ideal.

I'd be willing to put together a pull request for this, if you're open to it.

Repeatable not working

According to the docs it should possible to specify an option as repeatable to provide more than one value:

Command:

./script.js concat -f file1.txt -f file2.txt

Code:

program
  .version('1.0.0')
  .command('concat') // concat files
  .option('-f <file>', 'File to concat', program.REPEATABLE)
  .action(function(args: any, options: any) {
	console.log(JSON.stringify({args, options}));
  });

Expected result

{"args":{},"options":{"file": ["file1.txt", "file2.txt"]}}

Actual result

{"args":{},"options":{}}

Show help text programmatically

Expose a method to show the help string whenever I want to, like it being the default command of my program.

Program would be something like:

program
  .version(package.version)
  .action(() => program.showHelp())
  .command('real command')
  .action((args, options, logger) => /* do stuff */);
program.parse(process.argv);

// ./myprog
/* ... prints help ... */

I managed to print the help text using the private _help function, but as it's private and not documented, I believe it's not good to stick to it.

Have an option check for existence?

I have this right now:

.option("--json", "Output indexes in JSON format", prog.BOOL, false)

I'd like command --json to be interpreted as command --json=true but it does not be the same. Is there a way to enable this?

options not found unless a long option name set

I've discovered an issue whereby if you do not specify a long name for an option it results in no option being available as part of the options object when the action is called.

Consider the following

$ deploy -e staging   

// not working

prog.version('1.0.0')
    .command('deploy') // concat files
    .option('-e <environment>', 'deployment environment')
    .action(function(args, options) {
        console.log(args, options); // => {}, {} 
    });

prog.parse(process.argv);

// working

prog.version('1.0.0')
    .command('concat') // concat files
    .option('-e, --env <environment>', 'deployment environment')
    .action(function(args, options) {
        console.log(args, options); // => {}, { env : 'staging' } 
    });

You will notice that updating the option to the format of '-e, --env ' makes the option available.

It took me a while to track down the issue, but I believe the offending line which is causing this behaviour is in ./lib/command.js- #L315 , where camel case checks are performed. Should there be no long name defined then the option is not available.

Something along the lines of

_camelCaseOptions(options) {
  return this._options.reduce((acc, opt) => {

    const keyName = opt.name();

    if (typeof options[opt.getLongCleanName()] !== 'undefined') {
      acc[keyName] = options[opt.getLongCleanName()];
    } else {
      acc[keyName] = options[keyName];
    }
    return acc;
  }, {});
}

It wasn't immediately obvious this was the issue. I wonder if this could be addressed by updating the docs or amending the code to accommodate the scenario whereby a short name is only used.

Sub-commands

You say you took inspiration from commander js, from what I see you don't support sub-commands, which personally think is one of the most important features of a CLI framework. do you have plans for including a sub-command structure?

eg aws ec2 describe-instances

commander does this with a child process

and yargs supports this as well with require calls

program.command(require('./command.js'))

Changing the autogenerated help

Hi,

I'm trying to figure out a way to change the autogenerated help. Is it possible? I'd like to add some more lines to the end of it, including some examples.

Thanks for making this.
Caporal is working pretty well in my time tracker tool: Moro

Validate option to be a string

...
program
    .command('test', 'Some description')
    .option('--f', 'File')
...

I have a command like the one above, and if I use the --f option without a value, it will be true.
(my_program test --f). There should be a string validation too.

I made a temporary fix:

program.STRING = value => (typeof value === 'string' ? value : null);

...

program
    .command('test', 'Some description')
    .option('--f', 'File', program.STRING)

...

How to add global options?

What i want:

caporal
  .option('--foo', 'Show foo in all commands')

  .command('com1', '')
  .action((args, options) => {
    console.log(options.foo === true)
  })

  .command('com2', '')
  .action((args, options) => {
    console.log(options.foo === true)
  })

When I run:

program com1 --foo
# true

or

program --foo com2
# true

Do not print version if it's not defined

With the code

  orig
    .name('mycli')
    .description('My cli description')

the printed help will be:

mycli undefined - My cli description
     
   USAGE
   ....

If the version is not set, then it should be omitted in the help:

mycli - My cli description
     
   USAGE
   ....

Display the program name in USAGE

package.json allow to define a command name to run the cli, which might be different than the filename in which its implemented.

There is an undocumented name(string) function that allow to set the program name. The name set with this function is used to display the fist line of the help message but in the USAGE part.

For example with the following code:

// mycli.js
 prog.name('my-cly')
    .version('1.0.0')
    .description('My cli description')

The help will be:

   my-cli 1.0.0 - My cli description
     
   USAGE

     mycli.js 

But it should be:

   my-cli 1.0.0 -My cli description
     
   USAGE

     my-cli

prog.LIST are not parsed correctly

Hello,

It seems LIST are parse as comma separated string and not regular JSON arrays.

Sample code with caporal 0.8.0

#!/usr/bin/env node
const prog = require('caporal');
prog
  .version('1.0.0')
  .command('order pizza')
  .option('--number <num>', 'Number of pizza', prog.INT, 1)
  .option('--kind <kind>', 'Kind of pizza', /^margherita|hawaiian$/)
  .option('--discount <amount>', 'Discount offer', prog.FLOAT)
  .option('--add-ingredients <ingredients>', prog.LIST)
  .action(function(args, options) {
    console.log(options);
    console.log(options.addIngredients.length);
    // options.kind = 'margherita'
    // options.number = 1
    // options.addIngredients = ['pepperoni', 'onion']
    // options.discount = 1.25
  });

prog.parse(process.argv);

// ./myprog order pizza --kind margherita --discount=1.25 --add-ingredients=pepperoni,onion

Sample call

 ./myprog order pizza --kind margherita --discount=1.25 --add-ingredients=pepperoni,onion
{ number: 1,
  kind: 'margherita',
  discount: 1.25,
  addIngredients: 'pepperoni,onion' } // addIngredients should be ['pepperoni', 'onion']
15  // Length of options.addIngredients should be two not the total number of characters

Support for an "Examples" section

I use a CLI app that shows an Examples section in it's help page:

screen shot 2017-08-31 at 19 27 10

I think it would be pretty useful to have an #example API added to Caporal for showing something similar to this.

What do you think?

Argument flag order seems to be important

There is different behaviour between:

./program language -e name and ./program language name -e when program is defined as:

    program
        .command('language', 'create a language')
        .argument('[name]', 'name of the language', validateLanguageName)
        .option('-e --errorOnChange', 'error if the language file has changed')
        .action(createLanguage)

In the first case, name is never set and is sent to createLanguage as undefined. The validation function is never called either.
In the second case, name is set as expected.

Is this a feature or a bug? It seems to work against other CLIs which can take flags in any order.

_validateWithFlags breaks prog.LIST

@mattallty I was intending to use prog.LIST and was reviewing the pizza example and found that I was not getting the expected result.

Consider the following

-add-ingredients=a,b => { addIngredients : undefined }
-add-ingredients a,b => { addIngredients : [undefined, undefined }

I reviewed the code and the issue appears to be caused by _validateWithFlags and an omission of an early return statement when running in unary mode.

As the function calls itself for each value in the Array it will not pass the subsequent validation checks.

 _validateWithFlags(value, unary) {
    if (unary) { return value; } 
    ....
}

Though value.map and calling itself seems be redundant.

--no-color and --no-colors do not work (but --color=false does)

I was experimenting with your framework today (I like the built in logger stuff).

The README says I can deactivate the colors with --no-colors. The global options added to the help message by the framework say --no-color. Neither work and both result in an error :-(

Browsing the source and experimenting, revealed the magic option is --color=false.

Just thought I should point out that the README and the generated help are incorrect.

I like your framework. Nice work!

Variables with equal symbol

I'm trying to pass as variable something like --params="var1=val1, var2=val2" and receiving just var1 as result.
Is there some workaround or proper config?

Option validator - function

This example suggests the error message (throw new Error("You can only order margherita or hawaiian pizza!");) is returned when an error occurs. But I always get this message Error: Invalid value 'some option' for option --file. when I throw an error.

Is this a bug or the intended behavior?

Thanks for your feedback!

Logger should attach the new line character at the end of prettified message

I just logged some messages including strings and objects with following code.

.action(function(args, options, logger) {
  logger.warn('begin');
  logger.warn({ version: 'v1' });
  logger.warn({ version: 'v2' });
  logger.warn('end');
});

The logger does not print out each message in a proper way (i.e., each message in a line). The output is like below.

begin

version: v1
version: v2end

I suspect that the new line character should be attached at the end of prettified message in this code. I think it should be like this.

msg += prettyjson.render(meta) + "\n";

Not all options are considered

Something like this:

prog.option ( '--source, --src, -s <path>', '' );

Is supposed to be working, but only 2 flags are parsed at most.

All of them should be considered instead.

Add ability to hide a command from the help text

It's useful to have the ability to hide some commands from the help text, maybe they are supported but just for development and shouldn't be visible by default, but could be visible if executing my_app help --dev or something like that.

how can I generate routes template

example:

router.get('/${folder}', controller.${folder}.${folder}Find)
router.get('/${folder}/id/:id', controller.${folder}.${folder}FindById)
router.post('/${folder}', controller.${folder}.${folder}Create)
router.put('/${folder}/:id', controller.${folder}.${folder}Update)
router.delete('/${folder}/:id', controller.${folder}.${folder}Delete)

Sub-commands support

Feature request:
It is really helpful to have possibility for creating sub-commands like in many popular tools:

$ myprogram category command --options

This is especially helpful when your program contains generated list of commands

This would be really nice to be able to embed set of commands inside of other one.

Nice project, how do you do async?

I can't see here how you manage async actions for commands. You have promises in the complete() method, can I return a promise in an action and have it handled correctly?

Hard coded process argument

There is a reference to a hardcoded process argument in lib/program.js https://github.com/mattallty/Caporal.js/blob/master/lib/program.js#L24 This breaks our Electron application which does not contain a second argument when built. This property is not being used anywhere else in the code. In general, a library should not reference a hard coded value like that and should have sanity checks. Could you please fix that?

I've created a PR #45 but it does not pass the tests.

Thanks

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.