Skip to content

Commit

Permalink
[cli] Add Flag class #5
Browse files Browse the repository at this point in the history
- add flag and add flags is supported, but is used for generate help
  documentation mostly, not for retrieving values
- TODO: global flag support is partly implemented, trace back parent
  command to get all the global flags is needed.
  • Loading branch information
at15 committed Sep 12, 2016
1 parent 4fc9492 commit 1904a02
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 9 deletions.
9 changes: 7 additions & 2 deletions cmd/root.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ const versionCmd = require('./version');

let rootCmd = new Command();
rootCmd.name = 'about-cli';
rootCmd.description = 'A static about us/me & blog site generator, build with delay by @tongquhq';
rootCmd.registerCommand(versionCmd);
rootCmd.setFunc(() => {
console.log('I should show some help');
rootCmd.setFunc((app, args, flags) => {
if (flags.version) {
versionCmd.executeCurrent(app, args, flags);
return;
}
rootCmd.showHelp();
});

module.exports = rootCmd;
74 changes: 67 additions & 7 deletions lib/cli/command.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,23 @@ const logger = require('../logger');
* @property name {string}
* @property description {string}
* @property subCommands {Object.<string, Command>}
* @property supportedFlags {Object.<string, Flag>}
* @property supportedGlobalFlags {Object.<string, Flag>}
* @property flagAlias {Object.<string, string>}
* @property flagAliasReverse {Object.<string, string>}
*/
class Command {
constructor() {
this.app = {};
this.name = '';
this.description = '';
this.subCommands = {};
// * @property supportedFlags {Object.<
// * @property flagAlias {Object.<string, string>}
// this.supportedFlags = {};
// // global flags will pass to its sub commands
// this.supportedGlobalFlags = {};
// this.flagAlias = {};
this.supportedFlags = {};
// global flags is only global to its sub commands
this.supportedGlobalFlags = {};
// for quick lookup alias
this.flagAlias = {};
this.flagAliasReverse = {};
this.func = (app, args, flags) => {
};
}
Expand All @@ -35,6 +39,32 @@ class Command {
this.func = cb;
}

/***
*
* @param flag {Flag}
*/
addFlag(flag) {
if (flag.global === true) {
this.supportedGlobalFlags[flag.name] = flag;
} else {
this.supportedFlags[flag.name] = flag;
}
if (typeof flag.alias === 'string' && flag.alias !== '') {
this.flagAlias[flag.name] = flag.alias;
this.flagAliasReverse[flag.alias] = flag.name;
}
}

/***
*
* @param flags {Flag[]}
*/
addFlags(flags) {
_.forEach(flags, (flag) => {
this.addFlag(flag);
});
}

/**
*
* @param cmd {Command}
Expand Down Expand Up @@ -84,16 +114,46 @@ class Command {
}

executeCurrent(app, args, flags) {
flags = this.populateFlags(flags);
if (flags.help === true || flags.h === true) {
this.showHelp();
return;
}
this.func(app, args, flags);
}

// populate the flags
populateFlags(flags) {
let newFlags = _.assign(flags);
// basically it just deal with alias and nothing else, flags is still plain Object.<string, string|number|boolean>
_.forEach(flags, (value, key) => {
if (_.has(this.flagAlias, key)) {
newFlags[this.flagAlias[key]] = value;
}
// TODO: what if --config abc.yml -c abd.yml
if (_.has(this.flagAliasReverse, key)) {
newFlags[this.flagAliasReverse[key]] = value;
}
});
return newFlags;
}

showHelp() {
let helpMessage =
`${this.description}
`${this.description}
Usage:
Not supported
Available Commands:
Not supported
Flags:
Not supported
Global Flags:
Not supported
`;
// TODO: need to take global flag and local flag into consideration
// also flags need to have description
Expand Down
26 changes: 26 additions & 0 deletions lib/cli/flag.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/**
* Created by at15 on 2016/9/11.
*/
'use strict';

/**
* @property name {string}
* @property description {string}
* @property defaultValue {string|number|boolean}
* @property alias {string}
*/
class Flag {
constructor(name, description, defaultValue) {
this.name = name;
this.description = description;
this.defaultValue = defaultValue;
this.alias = '';
this.global = false;
}

setAlias(alias) {
this.alias = alias;
}
}

module.exports = Flag;
20 changes: 20 additions & 0 deletions test/cli/command-spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

const expect = require('chai').expect;
const Command = require('../../lib/cli/command');
const Flag = require('../../lib/cli/flag');

describe('Command', ()=> {
it('can register command', () => {
Expand Down Expand Up @@ -84,4 +85,23 @@ describe('Command', ()=> {
};
rootCmd.execute(null, [], {h: true});
});

it('can populate flag alias', ()=> {
let rootCmd = new Command();
rootCmd.name = 'dummy';
let verboseFlag = new Flag('verbose', 'verbose logging', false);
verboseFlag.alias = 'v';
verboseFlag.global = true;
rootCmd.addFlag(verboseFlag);
expect(rootCmd.supportedFlags).to.not.have.property('verbose');
expect(rootCmd.supportedGlobalFlags).to.have.property('verbose');
expect(rootCmd.flagAlias).to.eql({verbose: 'v'});
expect(rootCmd.flagAliasReverse).to.eql({v: 'verbose'});

let flags = rootCmd.populateFlags({verbose: true});
expect(flags).to.eql({verbose: true, v: true});
flags = rootCmd.populateFlags({v: true});
expect(flags).to.eql({verbose: true, v: true});

});
});

0 comments on commit 1904a02

Please sign in to comment.