庫 | 做用 |
---|---|
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 | 自動尋找 8000 至65535 內可用端口號 |
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交互工具庫 -- webpack-merge和webpack-chainjson
nodejs交互工具庫 -- strip-ansi, address, default-gateway和joivim
nodejs交互工具庫 -- fs-extra, Acorn和zlib
完整的 node.js 命令行解決方案
yarn add commander
爲簡化使用,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 型選項,選項無需配置參數,另外一類選項則能夠設置參數(使用尖括號聲明)。若是在命令行中不指定具體的選項及參數,則會被定義爲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 cheesenode 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 Commandererror: 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: 100node Commander -i 123
integer: 123node 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
時,若沒有指定其餘子命令,則會默認執行這個命令
基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔
一組通用的交互式命令行用戶界面。
努力爲Node.js(也許還有「CLI Xanadu」)提供一個容易嵌入和漂亮的命令行界面。
注意:
Inquirer.js
提供用戶界面和查詢會話流。若是您正在搜索一個完整的命令行程序實用程序,那麼請查看
commander,
vorpal or
args.
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
啓動提示界面(查詢會話)
Rx.Observable
實例)inquirer.registerPrompt(name, prompt)
在name下注冊提示插件
inquirer.createPromptModule() -> prompt function
建立一個自包含的查詢器模塊。若是您不但願在覆蓋或添加新的提示類型時影響一樣依賴於查詢器的其餘庫。
var prompt = inquirer.createPromptModule(); prompt(questions).then(/* ... */);
question object是一個包含問題相關值的 hash
input
- 可能的值 input
, number
, confirm
, list
, rawlist
, expand
, checkbox
, password
, editor
name
(後跟冒號)。numbers
、strings
或包含name
的objects
(在列表中顯示)、value
(保存在answers hash中)和short
屬性(在選擇後顯示)的對象。選擇數組還能夠包含一個分隔符。true
,不然返回錯誤消息(String
)。若是返回 false
,則提供一個默認的錯誤消息。list、rawList、expand
或checkbox
時將呈現的行數。默認狀況下,選擇(若是定義爲函數)、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); } }
在每一個提示符中包含客戶端答案的鍵/值散列。
name
屬性Value (取決於提示)
confirm
: (Boolean)input
: 用戶輸入(若是定義了過濾器,則進行篩選) (String)number
: 用戶輸入(若是定義了過濾器,則進行篩選) (Number)rawlist
, list
: 選擇的選擇值(若是沒有指定值,則爲name)(String)一個分隔符能夠添加到任何選擇數組:
// 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
。這將容許使用查詢器接口的工具檢測列表中的分隔符類型。
注意: 容許在方括號([])中寫入的選項是可選的。別人是必需的。
{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, ' ')); })
{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, ' ')); })
{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, ' ')); })
{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, ' ')); })
{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, ' ')); })
{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, ' ')); })
請注意,須要mask
來隱藏實際的用戶輸入。
{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, ' ')); })
顯示用戶類型的選項列表,與其餘包兼容,好比fuzzy(用於搜索)
帶有自動完成和其餘添加的複選框列表
使用數字鍵盤和箭頭鍵的可定製的日期/時間選擇器
提示在數組中選擇添加新元素的索引
簡單的提示與命令歷史和動態自動完成
提示選擇模糊文件/目錄。
輸入表情符號提示。
Prompt for input chalk-pipe style strings
可搜索的詢問者複選框
發出詢盤搜索列表
詢問者提示您缺少創造性的用戶。
用於查詢器的S3對象選擇器。
自動提交基於您當前的輸入,保存一個額外的輸入
詢問者提示選擇文件樹中的一個文件或目錄
詢問者的相似表格的提示。
基本經常使用的方法場景就這些了,更完整的用法能夠直接查閱文檔