Skip to content

Commit

Permalink
chore: Custom help implementation for displaying required flags (twil…
Browse files Browse the repository at this point in the history
  • Loading branch information
Anuj Badhwar committed Aug 25, 2021
1 parent 84ce7f4 commit ecc315a
Show file tree
Hide file tree
Showing 4 changed files with 159 additions and 1 deletion.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"s3": {
"bucket": "twilio-cli-prod"
}
}
},
"helpClass": "./src/services/twilio-help/custom-help"
}
}
10 changes: 10 additions & 0 deletions src/services/twilio-help/custom-help.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
const { Help } = require('@oclif/plugin-help');

const TwilioCommandHelp = require('./twilio-command-help');

module.exports = class TwilioHelp extends Help {
formatCommand(command) {
const help = new TwilioCommandHelp(command, this.config, this.opts);
return help.generate();
}
};
73 changes: 73 additions & 0 deletions src/services/twilio-help/twilio-command-help.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* eslint-disable import/no-extraneous-dependencies */
const CommandHelp = require('@oclif/plugin-help/lib/command.js');
const list = require('@oclif/plugin-help/lib/list');
const chalk = require('chalk');
const indent = require('indent-string');

/**
* Extended functionality from @oclif/plugin-help.
* Link: https://github.com/oclif/plugin-help
* author: onuzbee
*/
class TwilioCommandHelp extends CommandHelp.default {
// Override parent functionality
flags(flags) {
if (flags.length === 0) return '';

const optionalFlags = flags.filter((f) => !f.required);
const optionalBody = this.generateFlagsOutput(optionalFlags);
const requiredFlags = flags.filter((f) => f.required);
const requiredBody = this.generateFlagsOutput(requiredFlags);

const returnList = [chalk.bold('OPTIONS')];

if (requiredFlags.length > 0) {
returnList.push(chalk.bold('REQUIRED FLAGS'));
returnList.push(indent(requiredBody, 2));
}

returnList.push(chalk.bold('OPTIONAL FLAGS'));
returnList.push(indent(optionalBody, 2));
return returnList.join('\n');
}

/**
* Forked and refactored from oclif default implementation.
* Link: https://github.com/oclif/plugin-help/blob/master/src/command.ts#L125-L154
*/
generateFlagsOutput(flags) {
return list.renderList(
flags.map((flag) => {
let left = flag.helpLabel;
if (!left) {
const label = [];
if (flag.char) label.push(`-${flag.char[0]}`);
if (flag.name) {
if (flag.type === 'boolean' && flag.allowNo) {
label.push(`--[no-]${flag.name.trim()}`);
} else {
label.push(`--${flag.name.trim()}`);
}
}
left = label.join(', ');
}
if (flag.type === 'option') {
let value = flag.helpValue || flag.name;
if (!flag.helpValue && flag.options) {
value = flag.options.join('|');
}
if (!value.includes('|')) value = chalk.underline(value);
left += `=${value}`;
}
let right = flag.description || '';
if (flag.type === 'option' && flag.default) {
right = `[default: ${flag.default}] ${right}`;
}
return [left, chalk.dim(right.trim())];
}),
{ stripAnsi: this.opts.stripAnsi, maxWidth: this.opts.maxWidth - 2 },
);
}
}

module.exports = TwilioCommandHelp;
74 changes: 74 additions & 0 deletions test/services/twilio-help/twilio-help.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/* eslint-disable import/no-extraneous-dependencies */
const { expect, test } = require('@oclif/test');
const { Command, flags } = require('@oclif/command');
const stripAnsi = require('strip-ansi');

const TwilioHelp = require('../../../src/services/twilio-help/custom-help');

class DummyCommand extends Command {
constructor(argv, config) {
super(argv, config);
this.id = 'api:testHelp';
this.flags = {
app: flags.string({ char: 'a', hidden: true }),
force: flags.boolean({ description: 'force it '.repeat(4), allowNo: true }),
ss: flags.boolean({ description: 'newliney\n'.repeat(4) }),
remote: flags.string({ char: 'r' }),
def: flags.string({ char: 'd', default: 'default' }),
tst: flags.string({ char: 't', options: ['a', 'b', 'c'] }),
};
this.description = 'description of apps:create';
this.aliases = ['app:init', 'create'];
this.args = [{ name: 'app_name', description: 'app to use'.repeat(35) }];
}
}

const testHelp = test
.loadConfig()
.add('help', (ctx) => new TwilioHelp(ctx.config))
.register('commandHelp', (args, addReqFlag = false, emptyFlags = false) => {
return {
async run(ctx) {
const dummyHelpCommand = new DummyCommand(args, ctx.config);
if (addReqFlag) {
dummyHelpCommand.flags.foo = flags.string({ char: 'f', description: 'foobar'.repeat(15), required: true });
}

if (emptyFlags) {
dummyHelpCommand.flags = {};
}

const help = ctx.help.formatCommand(dummyHelpCommand);
ctx.commandHelp = stripAnsi(help)
.split('\n')
.map((s) => s.trimRight())
.join('\n');
},
};
});

describe('should log help', () => {
testHelp.commandHelp([], true).it('Should display required flags', (ctx) => {
expect(ctx.commandHelp).to.contain('api:testHelp');
expect(ctx.commandHelp).to.contain('OPTIONS');
expect(ctx.commandHelp).to.contain('REQUIRED FLAGS\n -f, --foo=foo');
expect(ctx.commandHelp).to.contain('OPTIONAL FLAGS');
expect(ctx.commandHelp).to.contain('USAGE');
});

testHelp.commandHelp([]).it('Should not display required flags if not configured', (ctx) => {
expect(ctx.commandHelp).to.contain('api:testHelp');
expect(ctx.commandHelp).to.contain('OPTIONS');
expect(ctx.commandHelp).to.not.contain('REQUIRED FLAGS');
expect(ctx.commandHelp).to.contain('OPTIONAL FLAGS');
expect(ctx.commandHelp).to.contain('USAGE');
});

testHelp.commandHelp([], false, true).it('Should not display Options in case no flags configured', (ctx) => {
expect(ctx.commandHelp).to.contain('api:testHelp');
expect(ctx.commandHelp).to.contain('USAGE');
expect(ctx.commandHelp).to.not.contain('OPTIONS');
expect(ctx.commandHelp).to.not.contain('REQUIRED FLAGS');
expect(ctx.commandHelp).to.not.contain('OPTIONAL FLAGS');
});
});

0 comments on commit ecc315a

Please sign in to comment.