Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #80: add autoHelpFlags #82

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module.exports = (helpMessage, opts) => {
input: 'string',
help: helpMessage,
autoHelp: true,
autoHelpFlags: true,
autoVersion: true
}, opts);

Expand Down Expand Up @@ -62,6 +63,64 @@ module.exports = (helpMessage, opts) => {

help = (description ? `\n ${description}\n` : '') + (help ? `\n${help}\n` : '\n');

if (opts.autoHelpFlags && opts.flags) {
const options = Object.keys(opts.flags).reduce((accum, flag) => {
const o = opts.flags[flag];
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use descriptive variable names.

if (Object.prototype.hasOwnProperty.call(o, 'default')) {
o.default = o.default.toString();
}

const option = {
flag: '',
value: '',
desc: ''
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
desc: ''
description: ''

};

if (flag.length === 1) {
o.alias = o.alias || flag;
}

option.flag += o.alias ? `-${o.alias}, ` : ' '.repeat(4);
option.flag += `--${flag === '--' ? '' : flag}`;
accum.flagMaxLen = Math.max(accum.flagMaxLen, option.flag.length);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
accum.flagMaxLen = Math.max(accum.flagMaxLen, option.flag.length);
accum.flagMaxLength = Math.max(accum.flagMaxLength, option.flag.length);


if (flag === '--') {
option.value = 'arg(s)';
} else if (o.type === 'boolean') {
option.value = '[true|false]';
} else {
option.value = `${o.default ? '[' : ''}<value>${o.default ? ']' : ''}`;
}
accum.valMaxLen = Math.max(accum.valMaxLen, option.value.length);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
accum.valMaxLen = Math.max(accum.valMaxLen, option.value.length);
accum.valueMaxLength = Math.max(accum.valueMaxLength, option.value.length);


if (flag === '--') {
option.desc = 'option/arg separator';
} else {
if (o.description) {
option.desc += o.description;
}
if (o.default) {
option.desc += `${o.description ? '; ' : ''}default ${o.default}`;
}
}

accum.entries.push(option);
return accum;
}, {
flagMaxLen: 0,
valMaxLen: 0,
entries: []
});

if (options.entries.length > 0) {
help += redent(options.entries.map(it =>
`${it.flag}${' '.repeat(options.flagMaxLen - it.flag.length + 2)}` +
`${it.value}${' '.repeat(options.valMaxLen - it.value.length + 2)}` +
it.desc
).join('\n'), 2);
}
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be moved to a top-level function. For readability and maintainability purposes.


const showHelp = code => {
console.log(help);
process.exit(typeof code === 'number' ? code : 2);
Expand Down
11 changes: 10 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ The key is the flag name and the value is an object with any of:
- `type`: Type of value. (Possible values: `string` `boolean`)
- `alias`: Usually used to define a short flag alias.
- `default`: Default value when the flag is not specified.
- `description`: Description to render when autogenerating flag help.

Example:

Expand All @@ -102,7 +103,8 @@ flags: {
unicorn: {
type: 'string',
alias: 'u',
default: 'rainbow'
default: 'rainbow',
description: 'Unicorn name'
}
}
```
Expand Down Expand Up @@ -148,6 +150,13 @@ Default: `true`

Automatically show the version text when the `--version` flag is present. Useful to set this value to `false` when a CLI manages child CLIs with their own version text.

##### autoHelpFlags
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a big fan of this option name. Can you suggest some other alternatives?


Type: `boolean`<br>
Default: `true`

Automatically show help on flags.

##### pkg

Type: `Object`<br>
Expand Down
22 changes: 21 additions & 1 deletion test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ test('return object', t => {
Usage
foo <input>
`,
autoHelpFlags: false,
flags: {
unicorn: {alias: 'u'},
meow: {default: 'dog'},
Expand All @@ -27,6 +28,25 @@ test('return object', t => {
t.is(cli.help, indentString('\nCLI app helper\n\nUsage\n foo <input>\n', 2));
});

test('return object with arg help', t => {
const cli = m({
argv: ['foo', '--foo-bar', '-u', 'cat', '--', 'unicorn', 'cake'],
flags: {
unicorn: {alias: 'u', description: 'Unicorn name'},
meow: {default: 'dog', description: 'What to meow'},
'--': true
}
});

t.is(cli.input[0], 'foo');
t.true(cli.flags.fooBar);
t.is(cli.flags.meow, 'dog');
t.is(cli.flags.unicorn, 'cat');
t.deepEqual(cli.flags['--'], ['unicorn', 'cake']);
t.is(cli.pkg.name, 'meow');
t.is(cli.help, indentString('\nCLI app helper\n\n-u, --unicorn <value> Unicorn name\n --meow [<value>] What to meow; default dog\n -- arg(s) option/arg separator', 2));
});
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This feature needs a lot more tests.


test('support help shortcut', t => {
const cli = m(`
unicorn
Expand All @@ -47,7 +67,7 @@ test('spawn cli and not show version', async t => {

test('spawn cli and show help screen', async t => {
const {stdout} = await execa('./fixture.js', ['--help']);
t.is(stdout, indentString('\nCustom description\n\nUsage\n foo <input>\n\n', 2));
t.is(stdout, indentString('\nCustom description\n\nUsage\n foo <input>\n\n-u, --unicorn <value> \n --meow [<value>] default dog\n --camelCaseOption [<value>] default foo', 2));
});

test('spawn cli and not show help screen', async t => {
Expand Down