node.js command line tutorial

Posted by seatoomol7 on Sun, 26 May 2019 22:57:54 +0200

node command line tutorial

This article first introduces the native node.js for command line interaction, understanding the native api, and then implementing a complete interactive command line tool using commander.js and inquirer.js.
Project Address

process

The process object is a global variable that provides information about and controls the current node.js process.Because it is a global variable, it does not need to be introduced in the file.

Several APIs needed

  • process.argv
  • process.cwd()
  • process.stdin
  • process.stdout
  • process.stdin.resume()

process.argv

The process.argv property returns an array.The first value of the array is process.execPath, the second is the file path of the JavaScript being executed, and the remaining parameters are other command parameters, which is the key to our custom command.

Example

New argv.js

//  argv.js
console.log(process.argv)

Execute node command node argv.js

node argv.js --name zhu
## output
[ '/usr/local/bin/node', ## Absolute path to the ode binary that executes the current script
  '/Users/zhuhuilong/Node/Book/argv.js', ## Absolute path to file
  '--name', ## Remaining parameters
  'zhu' ]

Receive custom command parameters to process output

//  argv.js
console.log(process.argv)

let argvs = process.argv

let param = argvs.splice(2)
if(param[0] && param[0] == '--name'){
  if(param[1]){
    console.log(`hello ${param[1]}`)
  }else{
    console.log('Please enter name')
  }
}

Run argv.js

node argv.js --name zhu
## output
[ '/usr/local/bin/node',
  '/Users/zhuhuilong/Node/Book/argv.js',
  '--name',
  'zhu' ]
hello zhu
param [ '--name', 'zhu' ]

process.stdin and process.stdout

Process.stdin (standard input)

The process.stdin property returns the stream connected to stdin (fd 0).It is a net.Socket stream (that is, a duplex stream), unless FD 0 points to a file, in which case it is a readable stream.

Process.stdout (standard output)

The process.stdout property returns the stream connected to stdout (fd 1).It is a net.Socket stream (that is, a duplex stream), unless FD 1 points to a file, in which case it is a writable stream.

process.stdin.resume()

  • A Readable Stream that points to a standard input stream (stdin).Standard input streams are paused by default, so you must call process.stdin.resume() to resume receiving.
  • As a stream, process.stdin can be used in old mode.In order to be compatible with versions prior to node v0.10.If you prefer to use stdin in the old mode, you must call process.stdin.resume().Note that if process.stdin.resume() is called, stdin will go into the old mode.

Generally speaking, the console waits for us to enter something without exiting the process and interacts with the input and output.

New inputout.js

// inputout.js
process.stdin.setEncoding('utf8')

let argvs = process.argv

let param = argvs.splice(2)
if (param[0] && param[0] == '--name') {
  if (param[1]) {
    console.log(`hello ${param[1]}`)
  } else {
    process.stdout.write(`Please enter name:`)
    process.stdin.resume()
    process.stdin.on('data', chunk => {
      if (!!chunk.replace(/[\r\n]/g, '')) {
        process.stdout.write(`The one you entered name yes: ${chunk}`)
        process.stdin.emit('end')
      } else {
        process.stdout.write(`Please enter name:`)
      }
    })
  }
}

process.stdin.on('end', () => {
  process.stdout.write('End\n')
})

>Execute node inputout.js --name

Remarks

In the new node mode, process.stdin.on ("readable", ()=>{}) can be used instead of process.stdin.resume() to restore input stream reception.

Example:

process.stdin.on("readable", () => {
  var chunk = process.stdin.read();
  console.log(typeof(chunk))
  if (chunk !==null) {
    process.stdout.write(`data: ${chunk}`);
    process.stdin.emit("end");
  }
});

process.stdin.on("end", () => {
  process.stdout.write("end");
});

From the example above, we can get the process.argv parameter to process the interaction, but if you want to achieve more complex command interaction, using the above method will be very difficult.Let's use commander.js and inquirer to implement a complete node command line tool (Create Project Template).

commander.js

The complete solution to the node.js command line interface was inspired by Ruby Commander.

A brief description of API for commander.js

program.version() declares version

const program = require('commander')
const pkg = require('../package.json')
program.version(pkg.version)

Options Resolution

Use the.option() method to define commander's options for options, which can also be used as documentation for options.

var program = require('commander');
 
program
  .version('0.1.0')
  .option('-p, --peppers', 'Add peppers')
  .option('-P, --pineapple', 'Add pineapple')
  .option('-b, --bbq-sauce', 'Add bbq sauce')
  .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')
  .parse(process.argv);
 
console.log('you ordered a pizza with:');
if (program.peppers) console.log('  - peppers');
if (program.pineapple) console.log('  - pineapple');
if (program.bbqSauce) console.log('  - bbq');
console.log('  - %s cheese', program.cheese);

Add custom command program.command()

var program = require('commander');
 
program
  .command('rm <dir>') //<>Required parameter, optional if []
  .option('-r, --recursive', 'Remove recursively')
  .action(function (dir, cmd) {
    console.log('remove ' + dir + (cmd.recursive ? ' recursively' : ''))
  })
 
program.parse(process.argv)

// command() variable parameters
/** command commands have and only the last parameter can be variable.To make the parameter variable variable variable, you must attach.. to the parameter name.**/
program
  .version('0.1.0')
  .command('rmdir <dir> [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);

program.action() defines the callback function of the command

var program = require("commander");

program
  .command("rm <dir>")
  .option("-r, --recursive", "Remove recursively")
  .option("-f, --force", "remove force")
  .action(function(dir, cmd) {
    // cmd is the option parameter option
    //console.log('cmd',cmd)
    if (cmd.recursive) {
      console.log("remove " + dir + " recursively");
    }
    if (cmd.force) {
      console.log("remove " + dir + " forcefully");
    }
  });

program.parse(process.argv);

inquirer.js

Inquirer.js A collection of generic interactive command line user interfaces made with NodeJs.There are common console interactions.

Because of the different types of interactive problems, inquirer provides many parameters for each problem:

  • Type: indicates the type of question, including: input, confirm, list, rawlist, expand, checkbox, password, editor;
  • name: The variable that stores the answer to the current question;
  • message: Description of the problem;
  • Default: default value;
  • choices: a list option that is available under certain type s and contains a separator;
  • validate: verify the user's answers;
  • Filter: filter the user's answers and return the processed values;
  • transformer: process the display effect of the user's answer (e.g., modify the font or background color of the answer), but it will not affect the content of the final answer;
  • when: Based on the answer to the previous question, determine if the current question needs to be answered;
  • pageSize: Modify the number of rendering rows for certain type s;
  • Prefix: Modify the default message prefix;
  • Suffix: Modify the message default suffix.

Create cli.js

const program = require('commander')
const inquirer = require('inquirer')
const fs = require('fs')
const path = require('path')
const pkg = require('../package.json')

const CWD = process.cwd()

const promptList = [
  {
    type: 'list',
    message: 'Please select a template',
    name: 'template',
    choices: ['vue', 'angular', 'webpack-m-pages'],
    filter: function(val) {
      return val.toLowerCase()
    }
  }
]

program
  .version(pkg.version)
  .command('create <dir>')
  .description('create project template')
  .action(function(dir, cmd) {
    const TEMPLATE_PATH = path.join(CWD, dir)
    if (fs.existsSync(TEMPLATE_PATH)) {
    } else {
      fs.mkdirSync(TEMPLATE_PATH)
    }
    if (dir) {
      inquirer.prompt(promptList).then(anwsers => {
        console.log(anwsers)
      })
    }
  })

program.parse(process.argv)

Run node cli/cli.js create vue

Now that it's ready to run, we customize a named replacement to execute node every time

The command is: test-cli create <dir>

1. Create a bin folder and an index.js file under the bin folder

#!/usr/bin/env node

require('../cli/cli')

2. Modify the package.json file
Add bin Option

"bin": {
    "test-cli": "./bin/index.js"
  },

3. Execute npm link (sudo npm link if no permission)

4. Testing

5. Publish npm publish (npm login first if not logged in)

6. After publishing, npm unlink is required to unmap local commands
npm install -g XXX

Topics: Javascript npm JSON socket Vue