Console

Console

There must have been situations where you would have made some temporary scripts to perform some tasks or even a permanent one. Intent comes with a @Command utility which you can use to create console commands in your applications.

It is not just a simple command line tool utility, but also comes integrated with argument, options parsing, styled console prints, interactive inputs, and also supports the NestJS DI lifecycle.

Creating Command

IntentModule automatically discovers all your console commands having @Command decorator attached to them.

There are two ways you can define commands in your application.

  • Using the @Command decorator on an Injectable class
  • Using the @Command decorator on an Injectable class' method.

Remember to use the @Injectable decorator on the class always, else the command will not be discovered and registered. Once the command is created, you can simply register it in the providers attribute of the app module.

If you want to automatically create the @Command class, you can simply run the following command.


$ node intent make:command NewCommand

This command will automatically create a newCommand.ts file in commands directory, and add it to the providers attribute of the app module class.

Using Class

You can create an injectable class and use @Command decorator on it. The package will automatically look for handle method inside the class.


import { Injectable, Command, ConsoleIO } from "@intentjs/core";
@Injectable()
@Command("hello {name=world}", { desc: "Test Command" })
export class HelloWorldCommand {
async handle(_cli: ConsoleIO): Promise<void> {
const name = _cli.argument<string>("name");
_cli.info(`Hello ${name}!`);
return;
}
}

Using Method

You can also use @Command decorator on the method.


import { Injectable, Command, ConsoleIO } from "@intentjs/core";
@Injectable()
export class HelloWorldCommand {
@Command("hello {name=world}", { desc: "Test Command" })
sayHello(_cli: ConsoleIO) {
const name = _cli.argument<string>("name");
_cli.info(`Hello ${name}!`);
return;
}
}

After creating the command, we need to now register it inside the app module.


import { HelloWorldCommand } from "./commands";
@Module({
providers: [HelloWorldCommand];
})
export class AppModule {}

Now, run the build command to transpile the project.


npm run build

Once the build is done, we can now run the command we created earlier.


node intent hello intent

Defining Input

Intent comes with some simple yet powerful argument and input parsers which help you pass input to your commands on the run time. There are three type of inputs which you can use as you like.

  • Arguments - These are mandatory input fields which is required at the runtime of the command.
  • Options - Similar to Arguments, but these are optional fields.
  • Prompt - These are programmatical prompts which you can use to prompt the user for custom interactive inputs.

Arguments

Arguments in console applications are required variables. These inputs are mandatory by nature, and not passing them would result in error.


@Command(
'hello {name}',
{ desc: 'Hello World Command' }
)

We can now pass your argument to the command as mentioned below


node intent generate:report ordersummay

You can use the argument method from the ConsoleIO helper to retrieve the input from the CLI.


async handle(_cli: ConsoleIO): Promise<void> {
const name = _cli.argument<string>("name");
}

You can also define default values for your arguments as,


@Command(
'hello {name=world}',
{ desc: 'Test Command' }
)

Now, if you don't pass any argument while invoking the hello command, you will get world as default value for the name argument.

In case you want to define an argument as of type array, you can simply add * (asterik) at the end of the argument.


"hello {name*}"

Now, all the values that you pass to the command, it will be collected under the name argument array.

If you want to make your arguments more declarative, or if you want to show the reference (manual) of the command on the console. You can also define description of each argument like mentioned below. Whatever sentence you write after : delimitter, it would be treated as description.


"hello {name : Name of the person to greet}";

Now try running the command with --help flag, you should see the description against the argument.

While arguments are great for times when you know the fixed set of inputs you are going to get. But we understand there are scenarios where some inputs can passed optionally, that is why we have added options alongside argument to help you do the same. Let's take a look.

Options

Options are the optional inputs for each command. They are denoted by double hyphens (--) or single hyphens (-).

Example:


@Command(
'hello {--name}',
{ desc: 'Command to greet the user' }
)

You can pass values to the options as mentioned below.


$ node intent hello --name=vinayak

To read the value from the console in your command, you can make use of the option method present inside the ConsoleIO.


const name = _cli.option<string>("name");

To pass array of values in any options or arguments, you can simply add an * (asterik).


hello {--names*}


$ node intent hello --name=vinayak --name=piyush

You can also define default values for the arguments or options by adding a = equal sign followed by the value.


hello {name=world} {--email=email@example.com}

You can also define short forms of the options like below


hello {--n|name}

Instead of using the full qualified name of the option, we can also use the short form as well.


$ node intent hello -n vinayak

To retrieve the input passed using the short forms of the options, you need to use only the full qualified name of the option.

Similar to arguments, you can also define description of the option.


"hello {--n|name : Name of the person to greet}";

Now try running the command with --help flag, you should see the description against the argument.

Retrieving Inputs

We provide easy to use APIs to work with I/O directly from the console.

While executing command, you will need to fetch the values that you may have passed during invoking the command. Your method will be passed an _cli: ConsoleIO object. You can use the `ConsoleIO` object to fetch your arguments or options.

For fetching an argument, you can do


const type = _cli.argument<string>("type");

For fetching an option, you can do


const email = _cli.option<string>("email");

If no value is passed, the argument and option function will return the default value or null value.

Prompts

You may want to ask for input while executing a command. We provide several ways with which you can ask for inputs directly on console.

To ask for simple input from the user, you can call ask() method.


const name = _cli.ask("name");

You may want to ask user about some secret or any password, which ideally should not get printed on the console.


const password = await _cli.password("Enter your pasword to continue");

While running a command, you can also give choices to select from a defined list. For example:


/**
* Single choice example.
* Returns one of the passed choices.
*/
const choice = await _cli.select(
"Please select one superhero", // question
["Batman", "Ironman"], // choices
false // multiple?
);
/**
* Multiple choices example.
* Returns an array of the selected options.
*/
const choice = await _cli.multiSelect("Please select one superhero", [
"Batman",
"Ironman",
]);

Lastly, sometimes you may want to ask for confirmation from the user before doing any execution. You can do so by using confirm method.


const confirm = await _cli.confirm("Do you really wish to continue?");
if (confirm) {
// do your magic here
}

Writing Outputs

Till now, we have seen how we can operate with differnt type of inputs on the cli. There will be scenarios when you will want to print something on the console. We provide a very easy-to-use set of APIs for your basic console outputing needs.

To print any message on the console, use info method


_cli.info("Some amazing message"); // Outputs 'Some amazing message' on the console

Incase of an error message, use error method.


_cli.error("Oops! Something went wrong.");

Similarly, to print any success message, use success method


_cli.success("Wohoo! The command worked just fine!");

To print a divider on the console, simple do


_cli.line();

To print a table on the console, you can use table method:


// this will automatically print unicode table on the console
_cli.table(
["Name", "Designation"],
[
{ name: "User 1", designation: "Software Engineer L1" },
{ name: "User 2", designation: "Software Engineer L1" },
]
);

Available Commands

We provide few commands, which will help in your day to day development process.

To list all commands available in your application, you can do


node intent list

list is a reserved command name, please don't use it in any of the commands

In-built Options

We provide few out-of-the-box predefined options, which you can use with each of your command.

To list all the arguments and options that your command supports/expects, simply run


node intent users:greet --help

--help is a reserved option. Please don't use it anywhere in your command.

;