nodejs交互工具庫 -- commander和Inquirer

nodejs交互工具庫系列

做用
chalk-pipe 使用更簡單的樣式字符串建立粉筆樣式方案
chalk 正確處理終端字符串樣式
Commander.js 完整的 node.js 命令行解決方案
Inquirer.js 一組通用的交互式命令行用戶界面。
slash 系統路徑符處理
minimist 解析參數選項
dotenv 將環境變量從 .env文件加載到process.env中
dotenv-expand 擴展計算機上已經存在的環境變量
hash-sum 很是快的惟一哈希生成器
deepmerge 深度合併兩個或多個對象的可枚舉屬性。
yaml-front-matter 解析yaml或json
resolve 實現node的 require.resolve()算法,這樣就能夠異步和同步地使用require.resolve()表明文件
semver npm的語義版本器
leven 測量兩字符串之間的差別<br/>最快的JS實現之一
lru cache 刪除最近最少使用的項的緩存對象
portfinder 自動尋找 800065535內可用端口號
ora 優雅的終端轉輪
envinfo 生成故障排除軟件問題(如操做系統、二進制版本、瀏覽器、已安裝語言等)時所需的通用詳細信息的報告
memfs 內存文件系統與Node's fs API相同實現
execa 針對人類的流程執行
webpack-merge 用於鏈接數組和合並對象,從而建立一個新對象
webpack-chain 使用鏈式API去生成簡化webpack版本配置的修改
strip-ansi 從字符串中去掉ANSI轉義碼
address 獲取當前機器的IP, MAC和DNS服務器。
default-gateway 經過對OS路由接口的exec調用得到機器的默認網關
joi JavaScript最強大的模式描述語言和數據驗證器。
fs-extra 添加了未包含在原生fs模塊中的文件系統方法,並向fs方法添加了promise支持
Acorn 一個小而快速的JavaScript解析器,徹底用JavaScript編寫。
zlib.js ZLIB.js是ZLIB(RFC1950), DEFLATE(RFC1951), GZIP(RFC1952)和PKZIP在JavaScript實現。

nodejs交互工具庫 -- chalk-pipe和chalknode

nodejs交互工具庫 -- commander和Inquirerreact

nodejs交互工具庫 -- slash, minimist和dotenv, dotenv-expandwebpack

nodejs交互工具庫 -- hash-sum, deepmerge和yaml-front-mattergit

nodejs交互工具庫 -- resolve和semvergithub

nodejs交互工具庫 -- leven, lru cache和portfinderweb

nodejs交互工具庫 -- ora和envinfo算法

nodejs交互工具庫 -- memfs和execanpm

nodejs交互工具庫 -- webpack-merge和webpack-chainjson

nodejs交互工具庫 -- strip-ansi, address, default-gateway和joivim

nodejs交互工具庫 -- fs-extra, Acorn和zlib

Commander.js

完整的 node.js 命令行解決方案

安裝

yarn add commander

聲明 program 變量

爲簡化使用,Commander 提供了一個全局對象。

const { program } = require('commander');
program.version('0.0.1');

若是程序較爲複雜,用戶須要以多種方式來使用 Commander,如單元測試等。建立本地 Command 對象是一種更好的方式:

const { Command } = require('commander');
const program = new Command();
program.version('0.0.1');

選項

Commander 使用.option() 方法來定義選項,同時能夠附加選項的簡介。每一個選項能夠定義一個短選項名稱(-後面接單個字符)和一個長選項名稱(--後面接一個或多個單詞),使用逗號、空格或|分隔。

選項能夠經過 Commander 對象的同名屬性獲取,對於多個單詞的長選項,使用駝峯法獲取,例如--template-engine與屬性program.templateEngine關聯。選項命名可參考避免選項命名衝突

多個短選項能夠合併簡寫,其中最後一個選項能夠附加參數。 例如,-a -b -p 80 也能夠寫爲 -ab -p80 ,甚至進一步簡化爲 -abp80

--能夠標記選項的結束,後續的參數均不會被命令解釋,能夠正常使用。 若是後續命令也須要設置選項,則能夠經過該方式實現,例如:do -- git --version

選項在命令行中的順序不固定,一個選項能夠在其餘選項以前或以後指定。

經常使用選項類型,boolean 型選項和帶參數選項

有兩種最經常使用的選項,一類是 boolean 型選項,選項無需配置參數,另外一類選項則能夠設置參數(使用尖括號聲明)。若是在命令行中不指定具體的選項及參數,則會被定義爲undefined

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

program
  .option('-d, --debug', 'output extra debugging')
  .option('-s, --small', 'small pizza size')
  .option('-p, --pizza-type <type>', 'flavour of pizza');

program.parse(process.argv);

if (program.debug) console.log(program.opts());
if (program.small) console.log('- small pizza size');
if (program.pizzaType) console.log(`- ${program.pizzaType}`);

經過program.parse(arguments)方法處理參數,沒有被使用的選項會存放在program.args數組中。

node commander -d -s -p 123
{ debug: true, small: true, pizzaType: '123' }

  • small pizza size
  • 123

選項的默認值

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

program
  .option('-c, --cheese <type>', 'add the specified type of cheese', 'blue');

program.parse(process.argv);

console.log(`cheese: ${program.cheese}`);
node commander
cheese: blue

可選參數

選項的參數使用方括號聲明表示參數是可選參數,即傳值不是必須的。

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

program
  .option('-c, --cheese [type]', 'Add cheese with optional type');

program.parse(process.argv);

if (program.cheese === undefined) console.log('no cheese');
else if (program.cheese === true) console.log('add cheese');
else console.log(`add cheese type ${program.cheese}`);
node commander
no cheese

node commander -c 123
add cheese type 123

必填選項

經過.requiredOption方法能夠設置選項爲必填。必填選項要麼設有默認值,要麼必須在命令行中輸入,對應的屬性字段在解析時一定會有賦值。該方法其他參數與.option一致。

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

program
  .requiredOption('-c, --cheese <type>', 'pizza must have cheese');

program.parse(process.argv);
node Commander

error: required option '-c, --cheese <type>' not specified

自定義選項處理

選項的參數能夠經過自定義函數來處理,該函數接收兩個參數:用戶新輸入的參數和當前已有的參數(即上一次調用自定義處理函數後的返回值),返回新的選項參數。

自定義函數適用場景包括參數類型轉換,參數暫存,或者其餘自定義處理的場景。

自定義函數能夠設置選項參數的默認值或初始值(例如參數用list暫存時須要設置一個初始空集合)。

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

function myParseInt(value, dummyPrevious) {
  // parseInt takes a string and an optional radix
  return parseInt(value);
}

function increaseVerbosity(dummyValue, previous) {
  return previous + 1;
}

program
  .option('-f, --float <number>', 'float argument', parseFloat)
  .option('-i, --integer <number>', 'integer argument', myParseInt)
  .option('-v, --verbose', 'verbosity that can be increased', increaseVerbosity, 0)
  ;

program.parse(process.argv);

if (program.float !== undefined) console.log(`float: ${program.float}`);
if (program.integer !== undefined) console.log(`integer: ${program.integer}`);
if (program.verbose > 0) console.log(`verbosity: ${program.verbose}`);
node Commander -f 1e2
float: 100

node Commander -i 123
integer: 123

node Commander -vvv
verbosity: 3

變長參數選項

定義選項時,能夠經過使用...來設置參數爲可變長參數。在命令行中,用戶能夠輸入多個參數,解析後會以數組形式存儲在對應屬性字段中。在輸入下一個選項前(-或--開頭),用戶輸入的指令均會被視做變長參數。與普通參數同樣的是,能夠經過--標記當前命令的結束。

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

program
  .option('-n, --number <numbers...>', 'specify numbers')
  .option('-l, --letter [letters...]', 'specify letters');

program.parse();

console.log('Options: ', program.opts());
console.log('Remaining arguments: ', program.args);
node Commander -n 1 2 3 --letter a b c
Options: { number: [ '1', '2', '3' ], letter: [ 'a', 'b', 'c' ] }
Remaining arguments: []

node Commander --letter=A -n80 operand
Options: { number: [ '80' ], letter: [ 'A' ] }
Remaining arguments: [ 'operand' ]

命令

經過.command().addCommand()能夠配置命令,有兩種實現方式:爲命令綁定處理函數,或者將命令單獨寫成一個可執行文件(詳述見後文)。子命令支持嵌套。

.command()的第一個參數能夠配置命令名稱及參數,參數支持必選(尖括號表示)、可選(方括號表示)及變長參數(點號表示,若是使用,只能是最後一個參數)。

使用.addCommand()program增長配置好的子命令。

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


// 經過綁定處理函數實現命令(這裏的指令描述爲放在`.command`中)
// 返回新生成的命令(即該子命令)以供繼續配置
program
  .command('clone <source> [destination]')
  .description('clone a repository into a newly created directory')
  .action((source, destination) => {
    console.log('clone command called');
  });


program.parse(process.argv);
node Commander clone ./123
clone command called

其餘用法以下

// 經過獨立的的可執行文件實現命令 (注意這裏指令描述是做爲`.command`的第二個參數)
// 返回最頂層的命令以供繼續添加子命令
program
  .command('start <service>', 'start named service')
  .command('stop [service]', 'stop named service, or all if no name supplied');

// 分別裝配命令
// 返回最頂層的命令以供繼續添加子命令
program
  .addCommand(build.makeBuildCommand());

使用.command()addCommand()來傳遞配置的選項。當opts.noHelp設置爲true時,該命令不會打印在幫助信息裏。當opts.isDefault設置爲true時,若沒有指定其餘子命令,則會默認執行這個命令

參考

基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔

commander.js

Inquirer.js

一組通用的交互式命令行用戶界面。

目標和理念

努力爲Node.js(也許還有「CLI Xanadu」)提供一個容易嵌入和漂亮的命令行界面。

  • 提供錯誤的反饋
  • 詢問交互
  • 解析輸入
  • 驗證答案
  • 層次提示管理
注意: Inquirer.js 提供用戶界面和查詢會話流。若是您正在搜索一個完整的命令行程序實用程序,那麼請查看 commander, vorpal or args.

Installation

yarn add inquirer
var inquirer = require('inquirer');
inquirer
  .prompt([
    /* Pass your questions in here */
  ])
  .then(answers => {
    // Use user feedback for... whatever!!
  })
  .catch(error => {
    if (error.isTtyError) {
      // Prompt couldn't be rendered in the current environment
    } else {
      // Something else when wrong
    }
  });

方法

inquirer.prompt(questions) -> promise

啓動提示界面(查詢會話)

inquirer.registerPrompt(name, prompt)

在name下注冊提示插件

inquirer.createPromptModule() -> prompt function

建立一個自包含的查詢器模塊。若是您不但願在覆蓋或添加新的提示類型時影響一樣依賴於查詢器的其餘庫。

var prompt = inquirer.createPromptModule();

prompt(questions).then(/* ... */);

Question Object

question object是一個包含問題相關值的 hash

  • type: (String) 提示符類型. 默認input - 可能的值 input, number, confirm, list, rawlist, expand, checkbox, password, editor
  • name: (String) 在answers hash中存儲答案時要使用的名稱。若是名稱包含句點,它將在answers散列中定義一個路徑。
  • message: (String|Function)打印的問題。若是定義爲函數,第一個參數將是當前查詢者會話的回答。默認值爲 name(後跟冒號)。
  • default: (String|Number|Boolean|Array|Function)不輸入任何內容時使用的默認值,或返回默認值的函數。若是定義爲函數,第一個參數將是當前查詢者會話的回答。
  • choices: (Array|Function) 選擇數組或函數返回的選擇數組。若是定義爲函數,第一個參數將是當前查詢者會話的回答。數組值能夠是簡單的numbersstrings或包含nameobjects(在列表中顯示)、value (保存在answers hash中)和short屬性(在選擇後顯示)的對象。選擇數組還能夠包含一個分隔符。
  • validate: (Function) 接收用戶輸入並answers hash。若是值有效,應該返回 true,不然返回錯誤消息(String)。若是返回 false,則提供一個默認的錯誤消息。
  • filter: (Function) 接收用戶輸入並answers hash。返回要在程序中使用的過濾後的值。返回的值將被添加到answers hash中。
  • transformer: (Function) 接收用戶輸入,answers hash和選項標誌,並返回轉換後的值以顯示給用戶。轉換隻影響編輯時顯示的內容。它不會修改answers hash。
  • when: (Function, Boolean) 接收當前用戶的answers hash,並根據是否應該問這個問題返回真或假。值也能夠是一個簡單的布爾值。
  • pageSize: (Number) 更改在使用 list、rawList、expandcheckbox時將呈現的行數。
  • prefix: (String) 更改默認的前綴消息。
  • suffix: (String) 更改默認後綴消息。
  • askAnswered: (Boolean) 若是答案已經存在,強制提示問題。
  • loop: (Boolean) 啓用列表循環。默認值:真

默認狀況下,選擇(若是定義爲函數)、validate, filter and when能夠異步調用函數。要麼返回一個promise,要麼使用 this.async()來得到一個回調,您將使用最終值調用它。

{
  /* Preferred way: with promise */
  filter() {
    return new Promise(/* etc... */);
  },

  /* Legacy way: with this.async */
  validate: function (input) {
    // Declare function as asynchronous, and save the done callback
    var done = this.async();

    // Do async stuff
    setTimeout(function() {
      if (typeof input !== 'number') {
        // Pass the return value in the done callback
        done('You need to provide a number');
        return;
      }
      // Pass the return value in the done callback
      done(null, true);
    }, 3000);
  }
}

Answers

在每一個提示符中包含客戶端答案的鍵/值散列。

  • Key 問題對象的 name屬性
  • Value (取決於提示)

    • confirm: (Boolean)
    • input : 用戶輸入(若是定義了過濾器,則進行篩選) (String)
    • number: 用戶輸入(若是定義了過濾器,則進行篩選) (Number)
    • rawlist, list : 選擇的選擇值(若是沒有指定值,則爲name)(String)

Separator

一個分隔符能夠添加到任何選擇數組:

// In the question object
choices: [ "Choice A", new inquirer.Separator(), "choice B" ]

// Which'll be displayed this way
[?] What do you want to do?
 > Order a pizza
   Make a reservation
   --------
   Ask opening hours
   Talk to the receptionist

構造函數接受一個兼性字符串值,它將用做分隔符。若是省略,分隔符將是--------

Separator實例的屬性類型等於separator。這將容許使用查詢器接口的工具檢測列表中的分隔符類型。

Prompt types

注意: 容許在方括號([])中寫入的選項是可選的。別人是必需的。

List - {type: 'list'}

使用 type, name, message, choices[, default, filter, loop] 屬性. (注意,默認值必須是數組中的選擇索引或選擇值)

var inquirer = require('inquirer');
inquirer
  .prompt([
    {
      type: 'list',
      name: 'theme',
      message: 'What do you want to do?',
      choices: [
        'Order a pizza',
        // 分隔符
        new inquirer.Separator(),
        // 禁止選擇
        {
          name: 'Contact support',
          disabled: 'Unavailable at this time',
        },
        'Talk to the receptionist',
      ],
    },
    {
      type: 'list',
      name: 'size',
      message: 'What size do you need?',
      choices: ['Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'],
      filter: function (val) {
        return val.toLowerCase();
      },
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image
image
image

Raw List - {type: 'rawlist'}

使用type, name, message, choices[, default, filter, loop] 屬性. (注意,默認值必須是數組中的選擇索引)

var inquirer = require('inquirer');
inquirer
  .prompt([
    {
      type: 'rawlist',
      name: 'theme',
      message: 'What do you want to do?',
      choices: [
        'Order a pizza',
        new inquirer.Separator(),
        'Ask opening hours',
      ],
    },
    {
      type: 'rawlist',
      name: 'size',
      message: 'What size do you need',
      choices: ['Jumbo', 'Large', 'Standard', 'Medium', 'Small', 'Micro'],
      filter: function (val) {
        return val.toLowerCase();
      },
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image
image
image

Expand - {type: 'expand'}

使用type, name, message, choices[, default] 屬性. (注意,默認值必須是數組中的選擇索引。若是沒有提供默認鍵,那麼幫助將被用做默認選項)

注意,選擇對象將接受一個名爲key的額外參數,用於展開提示符。該參數必須是單個(小寫)字符。h選項是由提示符添加的,不該該由用戶定義。

var inquirer = require('inquirer');
inquirer
  .prompt([
    {
      type: 'expand',
      message: 'Conflict on `file.js`: ',
      name: 'overwrite',
      choices: [
        {
          key: 'y',
          name: 'Overwrite',
          value: 'overwrite',
        },
        {
          key: 'a',
          name: 'Overwrite this one and all next',
          value: 'overwrite_all',
        },
      ],
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image
image

Checkbox - {type: 'checkbox'}

使用type, name, message, choices[, filter, validate, default, loop] 屬性. default 指望爲選中選項值的數組。

默認狀況下會選中標記爲{checked: true}的選項。

屬性disabled爲true的選項將沒法選擇。若是disabled是一個字符串,那麼這個字符串將被輸出到disabled選項旁邊,不然它將默認爲「Disabled」。禁用的屬性也能夠是一個同步函數,接收當前的答案做爲參數,並返回一個布爾值或字符串。

var inquirer = require('inquirer');
inquirer
  .prompt([
    {
      type: 'checkbox',
      message: 'Select toppings',
      name: 'toppings',
      choices: [
        new inquirer.Separator(' = The Meats = '),
        {
          name: 'Pepperoni',
        },
        {
          name: 'Ham',
        },
        new inquirer.Separator(' = The Cheeses = '),
        {
          name: 'Mozzarella',
          checked: true,
        },
        {
          name: 'Cheddar',
        },
      ],
      validate: function (answer) {
        if (answer.length < 1) {
          return 'You must choose at least one topping.';
        }

        return true;
      },
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image
image

Confirm - {type: 'confirm'}

使用type, name, message, [default] 屬性. default 指望是一個布爾值

var inquirer = require('inquirer');
inquirer
  .prompt([
    {
      type: 'confirm',
      name: 'toBeDelivered',
      message: 'Is this for delivery?',
      default: false,
    }
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image

Input - {type: 'input'}

使用type, name, message[, default, filter, validate, transformer] 屬性.

var inquirer = require('inquirer');
var chalkPipe = require('chalk-pipe');

const requireLetterAndNumber = (value) => {
  if (/\w/.test(value) && /\d/.test(value)) {
    return true;
  }

  return 'Password need to have at least a letter and a number';
};

inquirer
  .prompt([
    {
      type: 'input',
      name: 'name',
      message: "What's your first name",
    },
    {
      type: 'input',
      name: 'fav_color',
      message: "What's your favorite color",
      transformer: function (color, answers, flags) {
        const text = chalkPipe(color)(color);
        if (flags.isFinal) {
          return text + '!';
        }

        return text;
      },
    },
    {
      type: 'input',
      name: 'phone',
      message: "What's your phone number",
      validate: function (value) {
        var pass = value.match(
          /^([01]{1})?[-.\s]?\(?(\d{3})\)?[-.\s]?(\d{3})[-.\s]?(\d{4})\s?((?:#|ext\.?\s?|x\.?\s?){1}(?:\d+)?)?$/i
        );
        if (pass) {
          return true;
        }

        return 'Please enter a valid phone number';
      },
    },
    {
      type: 'password',
      message: 'Enter a password',
      name: 'password1',
      validate: requireLetterAndNumber,
    },
    {
      type: 'password',
      message: 'Enter a masked password',
      name: 'password2',
      mask: '*',
      validate: requireLetterAndNumber,
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image

請注意,須要mask來隱藏實際的用戶輸入。

Editor - {type: 'editor'}

使用type, name, message[, default, filter, validate] 屬性

在臨時文件上啓動用戶首選編輯器的實例。一旦用戶退出編輯器,就會將臨時文件的內容做爲結果讀入。要使用的編輯器是經過讀取$VISUAL$EDITOR 環境變量肯定的。若是二者都不存在,則使用notepad (Windows上的)或vim (Linux或Mac上的)。

var inquirer = require('inquirer');
var chalkPipe = require('chalk-pipe');

const requireLetterAndNumber = (value) => {
  if (/\w/.test(value) && /\d/.test(value)) {
    return true;
  }

  return 'Password need to have at least a letter and a number';
};

inquirer
  .prompt([
    {
      type: 'editor',
      name: 'bio',
      message: 'Please write a short bio of at least 3 lines.',
      validate: function (text) {
        if (text.split('\n').length < 3) {
          return 'Must be at least 3 lines.';
        }
  
        return true;
      },
    },
  ])
  .then(answers => {
    console.log(JSON.stringify(answers, null, '  '));
  })

image
image

Plugins

autocomplete

顯示用戶類型的選項列表,與其餘包兼容,好比fuzzy(用於搜索)
image

checkbox-plus

帶有自動完成和其餘添加的複選框列表
image

datetime

使用數字鍵盤和箭頭鍵的可定製的日期/時間選擇器
image

inquirer-select-line

提示在數組中選擇添加新元素的索引
image

command

簡單的提示與命令歷史和動態自動完成

inquirer-fuzzy-path

提示選擇模糊文件/目錄。
image

inquirer-emoji

輸入表情符號提示。
image

inquirer-chalk-pipe

Prompt for input chalk-pipe style strings

inquirer-search-checkbox

可搜索的詢問者複選框

inquirer-search-list

發出詢盤搜索列表
imageimage

inquirer-prompt-suggest

詢問者提示您缺少創造性的用戶。
image

inquirer-s3

用於查詢器的S3對象選擇器。
image

inquirer-autosubmit-prompt

自動提交基於您當前的輸入,保存一個額外的輸入

inquirer-file-tree-selection-prompt

詢問者提示選擇文件樹中的一個文件或目錄

inquirer-table-prompt

詢問者的相似表格的提示。
imageimage

參考

基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔

Inquirer.js

相關文章
相關標籤/搜索