This article refers to the Chinese document Commander. Js, playing with the Node command line with an old driver, and Inquirer

Commander.js

Provides the user command line input and parameter analysis of the powerful function, help us simplify the command line development, through the main command + sub-command + parameter mode to run the command, with the following features:

  • Argument parsing
  • Mandatory polymorphism
  • Variable parameter
  • Git style subcommands
  • Automated help information
  • Customize help

The preparatory work

To install commander. Js, run NPM install commander –save

demo

/// create any file in any directory, such as index.js const program = require("commander");

program
    .version("1.0.0")
    .parse(process.argv);   
Copy the code

You can see the output of the version information by executing node index.js -v from the console

API

The command instructions
.version Display version command, with the default option identified as-V--version, prints the version number when it exists and exits
. The parse and. ParseAsync Used to resolveprocess.argvTo set upoptionsAnd triggercommands(Parsing command line)
.option Define the options for the command
.requiredOption Set the option to mandatory, which either has a default value
. The command and. AddCommand Add command name
.alias Define an alias for the command
.usage Define the use of commands
.description Defines the description of the command
.action Defines the callback function for the command
.help(cb) Print help and exit immediately
.outputHelp(cb) Output help without exiting
.helpInformation() For in addition to--helpAdditional help information
.helpOption(flags, description) Overrides the default help identification and description
program.helpOption('-e, --HELP', 'read more information')
.addHelpCommand() Open or close (.addHelpCommand(false)Implicit help commands

version

In addition to using the default parameters, you can also customize the identity by passing an additional parameter to the version method with the same syntax as the option method

program.version('0.0.1'.'-v, --vers'.'output the current version')
Copy the code

. The parse and. ParseAsync

The first argument to.parse is the set of strings to parse. You can omit the argument to implicitly use process.argv

program.parse(process.argv); Parse (); // Explicit node convention program.parse(); // Implicit, automatically monitored electronCopy the code

The process.argv property returns an array containing the command line arguments passed in when the Node.js process is started. The first element is process.execPath (the absolute pathname of the executable that started the Node.js process). The second element is the path of the JavaScript file being executed. The remaining elements are any additional command-line arguments

If the argument follows a different convention than Node, you can pass the from option in the second argument:

program.parse(['-f'.'filename'], { from: 'user' });
Copy the code

Option,

Using the option () method defined commander options options, each of these options can have a short logo (single characters) and a long name, between them separated by commas or Spaces or ‘|’.

.option('-n, --name
      
       (custom label)'
      .'Name Description (option description)'.'Default name(default value)')
Copy the code

Option accepts three parameters:

  • Custom flags < must >: is divided intoLength of logoBetween,Comma, vertical line, or space; Flags can be followed by mandatory or optional parameters. The former is used<>Contains, the latter uses[]contains
  • Option Description < Optional >: Displays the flag description when using the –help command
  • Default value < optional >
  • Multi-word options such as“–template-engine”Will be converted to the hump methodprogram.templateEngine
  • Multiple short identifiers can be combined into a parameter starting with a dash: Boolean identifier and value, and the last identifier can have a value attached. For example,-a -b -p 80You can also write-ab -p80even-abp80

The two most common option types are Boolean (option followed by no value) and option followed by a value (declared with Angle brackets), both of which are undefined unless specified on the command line

const { program } = require("commander");

program
  .version("1.0.0")
  .option("-d, --debug"."output extra debugging")
  .option("-s, --small"."small pizza size")
  .option("-p, --pizza-type <type>"."flavour of pizza")
  .option("-c, --cheese <type>"."add the specified type of cheese"."blue")
  .parse(process.argv);

if (program.debug) console.log(program.opts());
console.log("pizza details:");
if (program.small) console.log("- small pizza size");
if (program.pizzaType) console.log(`- ${program.pizzaType}`);
Copy the code
  • Nodeindex. js –help Automatic help information help
/// Console output Usage: index [options] options: -v, --version output the version number-d, --debug              output extra debugging
  -s, --small              small pizza size
  -p, --pizza-type <type>  flavour of pizza
  -c, --cheese <type>      add the specified type of cheese (default: "blue")
  -h, --help               display help for command
Copy the code

Additional information can also be displayed by listening –help, which is triggered when the call is complete

  .on("--help", () => {
    console.log("");
    console.log("Example call :");
    console.log(" $ custom-help --help"); }) // Use.parse(process.argv) before parse; . $custom-help --help = $custom-help --helpCopy the code

In this case, the system automatically generates the usage information. You can set.usage and.name to specify the personalized help information

	.name("my-command")
  .usage("[global options] command") .parse(process.argv); . /// Console output Usage: my-command [global options]command// Previous Usage: index [options] options:Copy the code
  • node index.js -d
/// the console returns /// program.opts with all options set ///-dThe option is enabled, but the option is not followed by a value, so the corresponding value istrue{version: undefined;'1.0.0',
  debug: true, small: undefined, pizzaType: undefined} // Change the multi-word option to pizza details: cheese: blueCopy the code
  • node index.js -p
/// The console returns error: option'-p, --pizza-type <type>'Argument missing /// Because the argument after p is a necessary argumentCopy the code
  • node index.js -p vegetarian
/// console returns Pizza Details: - Vegetarian cheese: Blue... /// node index.js --pizza-type=vegetarianCopy the code
  • node index.js -ds
-ds {version:'1.0.0',
  debug: true,
  small: true,
  pizzaType: undefined }
pizza details:
- small pizza size
cheese: blue
Copy the code
  • Options default values will have an output above themcheese: bluethisblue-cIs the default value corresponding to
Nodeindex. js -c // error: option; // Error: option'-c, --cheese <type>' argument missing
Copy the code
  • use--To indicate the end of the option, and any remaining arguments will be used normally and will not be interpreted by the command
Nodeindex. js -- p; /// by definition, if you do not use -- the difference argument will be raised, and you will terminate without further explanationCopy the code
  • In order to--noA multiword option starting with a prefix is the inverse of the Boolean value of the option that follows it. For example,--no-sauceprogram.sauceIs set tofalse
const { program } = require('commander');
program
	.version('1.0.0')
	.option('-n --no-sauce'.'Remove sauce')
	.parse(process.argv);
	
if (program.sauce) console.log("sauce"); . /// Define it separately. The default value istrue
node index.js // { version: '1.0.0', sauce: true}... node index.js -n // { version:'1.0.0', sauce: false }
Copy the code

If you define –foo and then –no-foo doesn’t change its default value, you need to define it yourself

program
  .version("1.0.0")
  //   .option("-d, --debug"."output extra debugging")
  //   .option("-s, --small"."small pizza size")
  //   .option("-p, --pizza-type <type>"."flavour of pizza")
  //   .option("-c, --cheese <type>"."add the specified type of cheese"."blue")
  .option("-n --no-sauce"."Remove sauce")
  .option("-f --foo"."test foo")
  .option("-nf --no-foo"."test no foo")
  .parse(process.argv);

if(program.debug) console.log(program.opts()); console.log(program.opts()); . // if you define --foo, --no-foo, you have the default node index.js // {version:'1.0.0', sauce: true, foo: undefined } ... // nodeindex. js -nf // {version:'1.0.0', sauce: true, foo: false }
Copy the code
Custom option handling

Option can also define a custom processing function that takes two arguments: the value passed in by the user, the previous value, which returns the new option value (which can be cast to the desired type, or cumulative, or completely custom processing), specifying the option after the function as the default or initial value

Custom functions are applicable to parameter type conversion, parameter temporary storage, and other custom processing scenarios

const { program } = require("commander");

const setFoo = (value, previousValue) => {// The default value passed in is stringreturn Number(value) + 1;
};

program
  .version("1.0.0")
  .option("-f --foo <number>"."set foo info".setFoo) // The third argument receives the function. Parse (process.argv); console.log(program.opts()); . node index.js-f 21; // { version: '1.0.0', foo: 22} The received value is the processed valueCopy the code

Specify the value after the function

const { program } = require("commander");

const setFoo = (value, previousValue) => {
  console.log("value", value);
  console.log("proValue", previousValue);
  return Number(value) + 1;
};

program
  .version("1.0.0")
  .option("-F --Foo <number>"."set foo info".setFoo, 20) .parse(process.argv); console.log(program.opts()); . node index.js -F 10; . Value 10 // The function receives the user's passed value proValue 20 // 20 is set to the default value {version:'1.0.0', Foo: 11 }

Copy the code
Necessary options

You can specify a required (mandatory) option using.requiredOption, which can be specified or given a default value

const { program } = require("commander");

const setFoo = (value, previousValue) => {
  console.log("value", value);
  console.log("proValue", previousValue);
  return Number(value) + 1;
};

program
  .version("1.0.0")
  .requiredOption("-F --Foo <number>"."set foo info".setFoo, 20) .parse(process.argv); console.log(program.opts()); . node index.js; // { version:'1.0.0', Foo: 20} 20 is the default value /// Error: Required option is reported if the default value is deleted'-F --Foo <number>' not specified
Copy the code

command/addCommand

Define command line directives

.command('rmdir 
      
        [otherDirs...] (Command name)'
      .'Install description', OPTS (configuration options))Copy the code

Parameter analysis:

  • Command name < must > : The command can be followed by the command<> 或 []Included parameters; The last argument of the command can be mutable, appended to the array as in the example.Mark; Arguments passed after the command are passed toactionThe callback function andprogram.argsIn the array
  • Command description < omitted > : If there is, and no action(fn) is displayed, the subcommand program is started, otherwise an error is reported
  • Configuration option < omitted > : configurablenoHelp,isDefaultEtc.
const { program } = require("commander");

program
  .command("clone <source> [destination]")
  .description("clone a repository into a newly created directory"// Description can be absentcommandFill in the action ((source, destination) => {
    console.log(source); / / heresourcefromcommandConsole. log("clone command called"); }); program.parse(process.argv); console.log(program.args); . node index.jsclone/bash; /// console output /bash // in actionsource
clone command called
[ 'clone'.'/bash'] // This is program.args outputCopy the code
Specifying parameter syntax

Arguments can be specified for the top-level commands using.arguments, and for subcommands the arguments are in the corresponding.command callback.

Angle brackets <> indicate required input, and square brackets [] indicate optional input

const program = require("commander");

program
  .version("0.1.0 from")
  .arguments("<cmd> [env]")
  .action(function(cmd, env) {
    cmdValue = cmd;
    envValue = env;
  });

program.parse(process.argv);

if (typeof cmdValue === "undefined") {
  console.error("no command given!");
  process.exit(1);
}
console.log("command:", cmdValue);
console.log("environment:", envValue || "no environment given"); . Js CMD env // Corresponds to the top-level command parameters /// terminal outputcommand: cmd
environment: env
Copy the code

A command is called with the last and only variable argument written like the remaining arguments

const { program } = require("commander");

program
  .version("0.1.0 from")
  .command("rmdir 
      
        [otherDirs...] "
      )
  .action(function(dir, otherDirs) {
    console.log("rmdir %s", dir);
    if (otherDirs) {
      otherDirs.forEach(function(oDir) {
        console.log("rmdir %s", oDir); }); }}); program.parse(process.argv); . Nodeindex. js rmdir foo info // the terminal outputs rmdir foo rmdir infoCopy the code
Action handler for the subcommand

You can add an Action handler to the option of a subcommand. This callback takes two arguments. The first is the declared parameter variable, and the second command object itself.

const program = require("commander");

program
  .command("rm <dir>")
  .option("-r, --recursive"."Remove recursively")
  .action(function(dir, cmdObj) {
    console.log("remove " + dir + (cmdObj.recursive ? " recursively" : "")); }); program.parse(process.argv); . Nodeindex. js rm obj -r // Remove obj recursivelyCopy the code
Custom event listening

Listen for related options or commands through program.on()

const program = require("commander");
program.version("0.0.1").option("-l --list"."show list");

program.on("option:list".function() {
  console.log("option list call"); }); program.parse(process.argv); . node index.js-l/// The terminal outputs the Option list callCopy the code

inquirer.js

During the development process, we need frequent interaction with the command line, which can be easily achieved with the inquirer module, which provides the user interface and query session flow (that is, question-and-answer interaction).

The installation

npm i -S inquirer
Copy the code

Basic usage

const inquirer = require('inquirer'); Const promptList = [// Specific interaction content (list of questions)]; Inquirer. Prompt (promptList). Then (Answers => {// return result}). Catch (error => {if(error.isttyError) {// Unable to render prompt in the current environment}else{// other errors}});Copy the code

The format of the specific interaction content is as follows:

{
    type: "input",
    message: "Set a user name :",
    name: "name",
    default: "test_user"// Default value}Copy the code

Here is a complete example

const inquirer = require("inquirer");

const promptList = [
  {
    type: "input",
    message: "Set a user name :",
    name: "name",
    default: "test_user"// Default value}]; inquirer.prompt(promptList).then(answer => { console.log(answer); });Copy the code

API

parameter type describe
type String Indicates the type of question
includingInput (default).number.confirm.list.rawlist.expand.checkbox.password.editor
name String The variable that stores the current question answer
message “String Function“
default “String Number
choices “Array Function“
validate Function Verify the user’s answers
filter Function Filter the user’s answers and return the processed value
transformer Function Processing the display effect of the user’s answer (e.g. changing the font or background color of the answer), but will not affect the content of the final answer;
when Function, Boolean Determine whether the current question needs to be answered based on the answers to the previous questions
pageSize Number Modifies the number of rendered lines for certain types
prefix String Modify the default message prefix
suffix String Modify the default message suffix
askAnswered Boolean If the answer already exists, the question is forced
loop Boolean Enable list loops (default true)

Common examples

input

const promptList = [
  {
    type: "input",
    message: "Set a user name :",
    name: "name",
    default: "test_user"// Default value}, {type: "input",
    message: "Please enter your mobile number :",
    name: "phone",
    validate: function(val) {// validate exampleif(/^1[3456789]\d{9}$/.test(val)) {// Verify that the phone number is correctreturn true;
      }
      return "Please enter the correct phone number."; }}];Copy the code

number

const promptList = [
  {
    type: "number",
    message: "Your mobile number :",
    name: "phone"}];Copy the code

Input that is not a number is converted to NaN, which is a bit of an input sugar. Input and validate do the same thing

confirm

const promptList = [
  {
    type: "confirm",
    message: "Is listening used?",
    name: "watch",
    prefix: "Prefix"
  },
  {
    type: "confirm",
    message: "Is file filtering enabled?",
    name: "filter",
    suffix: "Suffix",
    when: function(answers) {// The answer to the previous question istrueShow the problem when (use when)returnanswers.watch; }}];Copy the code

list

const promptList = [
  {
    type: "list",
    message: "Please choose a fruit :",
    name: "fruit",
    choices: ["Apple"."Pear"."Banana"],
    filter: function(val) {// Use filter to change the answer to lowercasereturnval.toLowerCase(); }}];Copy the code

rawlist

Just like list, it’s a list presentation, and this one will display the numbers

const promptList = [
  {
    type: "rawlist",
    message: "Please choose a fruit :",
    name: "fruit",
    choices: ["Apple"."Pear"."Banana"]}];Copy the code

expand

Specifies the associative input for the command

const promptList = [
  {
    type: "expand",
    message: "Please choose a fruit:",
    name: "fruit",
    choices: [
      {
        key: "a",
        name: "Apple",
        value: "apple"
      },
      {
        key: "O",
        name: "Orange",
        value: "orange"
      },
      {
        key: "p",
        name: "Pear",
        value: "pear"}}]];Copy the code

You can only enter a, O, and P parameters. If you intentionally enter wrong parameters, press OK to convert these questions to rawList for selection

checkbox

const promptList = [
  {
    type: "checkbox",
    message: "Select color :",
    name: "color",
    choices: [
      {
        name: "red"}, new inquire.separator (), // Add Separator {name:"blur",
        checked: true}, {name:"green"
      },
      new inquirer.Separator("-- delimiter --"), // Custom delimiter {name:"yellow"}}]];Copy the code

Invert Selection: Press

to select,
to toggle all, < I > to invert Selection Press

to select,

to toggle all, < I > to invert Selection

/// There is another format const promptList = [{type: "checkbox",
    message: "Select color :",
    name: "color",
    choices: ["red"."blur"."green"."yellow"], pageSize: 2}];Copy the code

In this mode, you can set the number of lines to be displayed. You can use the up and down arrow keys to view the options. If the option is to loop, you can set loop: false to disable it

password

const promptList = [
  {
    type: "password"// If the password is ciphertext, enter message:"Please enter your password:",
    name: "pwd"}];Copy the code

editor

const promptList = [
  {
    type: "editor",
    message: "Please enter remarks:",
    name: "editor"}];Copy the code

This will bring you to a Vim editor

The plug-in

In addition to the type type mentioned above, Inquirer. Js provides customizable plug-in method inquirer. RegisterPrompt (name, prompt) (the method used above is inquirer. The community already has some good plugins

inquirer-table-prompt

This is a table plugin that works well for scenarios where there is a lot of choice (see inquirer’s Github page for other plugins).

const inquirer = require("inquirer"); Inquirer. RegisterPrompt ()"table", require("inquirer-table-prompt"));

const promptList = [
  {
    type: "table"// The first parameter to registerPrompt, the second parameter is to import the related library name:"workoutPlan",
    message: "Choose your workout plan for next week",
    columns: [
      {
        name: "Arms",
        value: "arms"
      },
      {
        name: "Legs",
        value: "legs"
      },
      {
        name: "Cardio",
        value: "cardio"
      },
      {
        name: "None",
        value: undefined
      }
    ],
    rows: [
      {
        name: "Monday",
        value: 0
      },
      {
        name: "Tuesday",
        value: 1
      },
      {
        name: "Wednesday",
        value: 2
      },
      {
        name: "Thursday",
        value: 3
      },
      {
        name: "Friday",
        value: 4
      },
      {
        name: "Saturday",
        value: 5
      },
      {
        name: "Sunday",
        value: 6
      }
    ]
  }
];

inquirer.prompt(promptList).then(answer => {
  console.log(answer);
});

Copy the code

chalk.js

A beautify plugin, node terminal style library, no special introduction, specific color and API refer to the official documentation

We can use this library to add some colors to the interactive commands we write to make it easier to see the difference

const chalk = require("chalk");

const promptList = [
  {
    type: "number",
    message: "Your mobile number :",
    name: "phone",
    validate: function(val) {// validate exampleif(/^1[3456789]\d{9}$/.test(val)) {// Verify that the phone number is correctreturn true;
      }
      return chalk.red("Please enter the correct phone number."); // Wrap the part that needs to change color}}];Copy the code