Skip to content

Commit

Permalink
useSubcommand draft
Browse files Browse the repository at this point in the history
  • Loading branch information
a-fas committed Sep 16, 2019
1 parent 73518f2 commit 372b7be
Show file tree
Hide file tree
Showing 3 changed files with 107 additions and 0 deletions.
58 changes: 58 additions & 0 deletions examples/use-subcommand.js
@@ -0,0 +1,58 @@
#!/usr/bin/env node

// This is an example of useSubcommand
//
// $ use-subcommand journal list myjounal
// $ use-subcommand journal delete myjounal
//
// With options
// $ use-subcommand journal -q delete -f myjounal

// const { Command } = require('commander');
const { Command } = require('..');

function importSubCommand() {
const journalCmd = new Command()
.name('journal')
.description('Journal utils');

journalCmd
.command('list <path>')
.description('List journal')
.action((path, cmdInstance) => {
console.log('List journal');
console.log('Path is', path);
console.log('Quiet =', Boolean(cmdInstance.parent.quiet));
});

journalCmd
.command('delete <path>')
.description('Delete journal')
.option('-f, --force')
.action((path, cmdInstance) => {
console.log('List journal');
console.log('Path is', path);
console.log('Quiet =', Boolean(cmdInstance.parent.quiet));
console.log('Force =', Boolean(cmdInstance.force));
});

return journalCmd;
}

// this is supposedly a module, so in real case this would be `require`
const journalSubCommand = importSubCommand();

const program = new Command();
program
.option('-q, --quiet')
.useSubcommand(journalSubCommand);

program
.command('hello <name>')
.description('Greeting')
.action((name, cmdInstance) => {
console.log(`Hello ${name}!`);
});

if (process.argv.length <= 2) program.help();
program.parse(process.argv);
40 changes: 40 additions & 0 deletions index.js
Expand Up @@ -1210,6 +1210,46 @@ Command.prototype.help = function(cb) {
process.exit();
};

/**
* Add action-like sub command
* command name is taken from name() property - must be defined
*
* @returns {Command} `this` instance
*/

Command.prototype.useSubcommand = function(subCommand) {
if (this._args.length > 0) throw Error('useSubcommand cannot be applied to a command with explicit args');
if (!subCommand._name) throw Error('subCommand name is not specified');

var self = subCommand;
var listener = function(args, unknown) {
// Parse any so-far unknown options
args = args || [];
unknown = unknown || [];

var parsed = self.parseOptions(unknown);
if (parsed.args.length) args = parsed.args.concat(args);
unknown = parsed.unknown;

// Output help if necessary
const helpRequested = unknown.includes('--help') || unknown.includes('-h');
const noFutherCommands = !args || !self.listeners('command:' + args[0]);
if (helpRequested && noFutherCommands) {
self.outputHelp();
process.exit(0);
}

self.parseArgs(args, unknown);
};

for (const label of [subCommand._name, subCommand._alias]) {
if (label) this.on('command:' + label, listener);
}
this.commands.push(subCommand);
subCommand.parent = this;

This comment has been minimized.

Copy link
@a-fas

a-fas Sep 16, 2019

Author

subCommand.parent = this;
This line makes me uncomfortable - modifying the parameter. But not sure how to workaround

return this;
};

/**
* Creates an instance of sub command
*
Expand Down
9 changes: 9 additions & 0 deletions typings/index.d.ts
Expand Up @@ -204,6 +204,15 @@ declare namespace local {

forwardSubcommands(): Command;

/**
* Add action-like sub command
* command name is taken from name() property - must be defined
*
* @returns {Command} `this` instance
*/

useSubcommand(subCommand : Command): Command;

/**
* Returns an object with all options values, including parent options values
* This makes it especially useful with forwardSubcommands as it collects
Expand Down

0 comments on commit 372b7be

Please sign in to comment.