Skip to content
Merged
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
37 changes: 33 additions & 4 deletions src/command-help.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Command } from './command';
import { CommandOption, OptionType } from './command-options';

export class CommandHelp {
public constructor(public command: Command) {}
Expand Down Expand Up @@ -37,17 +38,45 @@ export class CommandHelp {

public showPositional() {
for (const positional of this.command.positional) {
console.log(` <${positional.key}>: ${positional.description}`);
this.showCommandOption(positional, true);
}
}

public showOptions() {
for (const option of this.command.options) {
const key = `--${option.key}`;
const alias = option.alias ? ` -${option.alias}` : '';
console.log(` ${key}${alias}: ${option.description}`);
this.showCommandOption(option);
}
}

public showCommandOption(option: CommandOption, isPositional = false) {
let key = '';

if (isPositional) {
key = `<${option.key}>`;
}
else {
if (option.alias) {
key = `-${option.alias}, `;
}

key += `--${option.key}`;
}

const type =
option.type && option.type !== OptionType.string
? ` {${option.type}}`
: '';
const defaultValue =
option.default !== undefined ? ` (default: ${option.default})` : '';
const choices = option.choices
? ` [choices: ${option.choices.join(', ')}]`
: '';
const description = option.description ?? '';
const metadata = `${type}${defaultValue}${choices}`;
const fullDescription = `${description}${metadata}`;

console.log(` ${key}: ${fullDescription}`);
}

public footer() {}
}
6 changes: 3 additions & 3 deletions src/command-options.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { ArgumentValue } from './argument-parser';

export enum OptionType {
boolean,
number,
string,
boolean = 'bool',
number = 'number',
string = 'string',
}

export interface CommandOption {
Expand Down
85 changes: 82 additions & 3 deletions test/spec/command-help.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import { MockConsole } from 'ts-jasmine-spies';
import { MockCommand } from '../mock/mock-command';
import { CommandHelp } from '../../src/command-help';
import { CommandOption, OptionType } from '../../src/command-options';

class HelpTestCommand extends MockCommand {
override key = 'test';
override description = 'Test command description';

override positional = [
override positional: CommandOption[] = [
{ key: 'arg1', description: 'First argument' },
{ key: 'arg2', description: 'Second argument' },
];

override options = [
override options: CommandOption[] = [
{ key: 'opt1', description: 'First option', alias: 'o' },
{ key: 'opt2', description: 'Second option', alias: undefined },
];
Expand Down Expand Up @@ -53,7 +54,85 @@ describe('CommandHelp', () => {
it('can show optional arguments', () => {
commandHelp.showOptions();
mockConsole.expectStdout(
' --opt1 -o: First option\n --opt2: Second option\n'
' -o, --opt1: First option\n --opt2: Second option\n'
);
});

it('shows option default value', () => {
mockCommand.options = [
{
key: 'opt1',
description: 'First option',
default: 'defaultValue',
},
];

commandHelp.showOptions();
mockConsole.expectStdout(
' --opt1: First option (default: defaultValue)\n'
);
});

it('can show option without description', () => {
mockCommand.options = [{ key: 'opt1', default: 'defaultValue' }];
commandHelp.showOptions();
mockConsole.expectStdout(' --opt1: (default: defaultValue)\n');
});

it('shows option choices', () => {
mockCommand.options = [
{
key: 'opt1',
description: 'First option',
choices: ['choice1', 'choice2'],
},
];

commandHelp.showOptions();
mockConsole.expectStdout(
' --opt1: First option [choices: choice1, choice2]\n'
);
});

it('shows option type', () => {
mockCommand.options = [
{
key: 'opt1',
description: 'First option',
type: OptionType.number,
},
];

commandHelp.showOptions();
mockConsole.expectStdout(' --opt1: First option {number}\n');
});

it('shows skips option type for strings', () => {
mockCommand.options = [
{
key: 'opt1',
description: 'First option',
},
];

commandHelp.showOptions();
mockConsole.expectStdout(' --opt1: First option\n');
});

it('shows default value and choices', () => {
mockCommand.options = [
{
key: 'opt1',
description: 'First option',
default: 'defaultValue',
choices: ['choice1', 'choice2'],
type: OptionType.string,
},
];
commandHelp.showOptions();
mockConsole.expectStdout(
' --opt1: First option (default: defaultValue)' +
' [choices: choice1, choice2]\n'
);
});

Expand Down