Optimizing Nest-Commander: User Inputs

thebenforce

Ben Force

Posted on September 26, 2023

Optimizing Nest-Commander: User Inputs

In my previous article, you created a NestJS CLI application. It was a very basic starting point that printed a cow saying a static message in the console.

But what if your users demand the ability to display custom messages? That's what you're going to add in this article. The new and improved application will display the same message by default, or any string that you pass in with the --message argument.

Adding a Message Option

The easiest way to add an option is to add a parser function for a parameter and add the @Option decorator to it.

In the cow-say.command.ts file, add the following method to your CowSayCommand class.

@Option({
  flags: '--message <message>',
  description: 'The message we want to see the cow say',
})
parseMessage(value: string) {
  return value;
}
Enter fullscreen mode Exit fullscreen mode

Decorating It

If you've used the commander library before, this should look familiar. The <message> tells commander that if the --message option is provided, the user doesn't need to provide a parameter after it. If the value was required it would be [message] instead.

The description parameter is used when the user displays help for a specific command. The description will be displayed in a column to the right of every available option.

The Parser

The @Option decorator is applied to a parser function, in this case parseMessage. The function takes in a string and needs to convert it to whatever type you'll want at runtime. If you had a --count <count> parameter, you'd need to convert a string to an integer.

Since the message should be a string, you just need to return it. Nothing fancy here.

Using the Options

To use the option, you need to accept two parameters in the run method. The first is an array of parameters that were passed in, and the second is an options object that includes all of the parsed options. Since you aren't using the parameters you can just ignore it.

async run(_passedParams: string[], options: { message?: string }): Promise<void> {
  const message = options.message ?? 'Hello World!';

  console.log(cowsay.say({ text: message }));
}
Enter fullscreen mode Exit fullscreen mode

Awesome, now if you run the program with a --message "Foo Bar" parameter, the cow will be saying "Foo Bar".

Using Inquirer

Using parsers like in the previous step works great for smaller commands. It has the advantage of being simple. But what if you would like to gracefully ask the user to enter any parameters they forgot to provide? For that, you can use the InquirerService.

The first thing you need to do is define the types of inputs that will be used for each parameter. That's done with a class decorated with @QuestionSet and parsing methods decorated with @Question.

Create a cow-say.questions.ts file and add the following to it.

import { Question, QuestionSet } from 'nest-commander';

@QuestionSet({
  name: 'cowSay',
})
export class CowSayQuestions {
  @Question({
    type: 'input',
    name: 'message',
    message: 'What does the cow say?',
  })
  parseMessage(value: string) {
    return value;
  }
}
Enter fullscreen mode Exit fullscreen mode

Now add this class as a provider to your module.

...
import { CowSayQuestions } from './cow-say.questions';

@Module({
  providers: [CowSayCommand, CowSayQuestions],
})
export class CowSayModule {}
Enter fullscreen mode Exit fullscreen mode

Now the message parameter needs to be updated to be mandatory in the command.

@Option({
    flags: '--message [message]',
    description: 'The message we want to see the cow say',
  })
Enter fullscreen mode Exit fullscreen mode

Next, inject the inquirer service into the command.

constructor(private readonly inquiererService: InquirerService) {
  super();
}
Enter fullscreen mode Exit fullscreen mode

Finally, update the run method and use the inquirer service to update the options parameter.

options = await this.inquiererService.ask('cowSay', options);

console.log(cowsay.say({ text: options.message }));
Enter fullscreen mode Exit fullscreen mode

Now, when you run the command if you don't pass in the --message option the application will ask you to provide it.

 npm run start:cli   

> my-cli-project@0.0.1 start:cli
> ts-node src/main.ts

? What does the cow say? Mooooooo
 __________
< Mooooooo >
 ----------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Enter fullscreen mode Exit fullscreen mode

Summary

In this article, you expanded upon the basic NestJS CLI application created in the previous installment. You learned how to add arguments with an option parser function and used the @Option decorator. You also learned how to use the InquirerService to gracefully prompt users to enter missing parameters and integrated it into your command, enhancing user interaction.

💖 💪 🙅 🚩
thebenforce
Ben Force

Posted on September 26, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related