本文带你了解建立一个Node-CLI工具所需知识点。javascript
在NodeJS中能够经过如下代码获取命令行中传递的参数:css
process.argv.slice(2)
复制代码
可是这对于构建一个CLI工具远远不够,首先须要考虑参数输入的各类风格:html
这里能够经过正则表达式对process.argv进行加工:vue
/** * 解析Unix、BSD和GNU参数风格 * @param {Array} argv 命令行参数数组 * @returns */
function parseArgv (argv) {
const max = argv.length
const result = {
_: []
}
for (let i = 0; i < max; i++) {
const arg = argv[i]
const next = argv[i + 1]
if (/^--.+/.test(arg)) {
// GNU风格
const key = arg.match(/^--(.+)/)[1]
if (next != null && !/^-.+/.test(next)) {
result[key] = next
i++
} else {
result[key] = true
}
} else if (/^-[^-]+/.test(arg)) {
// Unix风格
const items = arg.match(/^-([^-]+)/)[1].split('')
for (let j = 0, max = items.length; j < max; j++) {
const item = items[j]
// 非字母不解析
if (!/[a-zA-Z]/.test(item)) {
continue
}
if (next != null && !/^-.+/.test(next) && j === max - 1) {
result[item] = next
i++
} else {
result[item] = true
}
}
} else {
// BSD风格
result._.push(arg)
}
}
return result
}
复制代码
经过以上的方法能够获得以下结果:java
node example1.js --save-dev -age 20 some
// => 结果
{
_: ['some'],
'save-dev': true,
a: true,
g: true,
e: 20
}
复制代码
上面这个示例不单单为了展现解析的结果,并且还强调了Unix参数风格只解析单个字母,因此这种风格的参数可能表达的意思不太明确而且数量有限,那么就须要在正确的场景中使用这种风格的参数:node
npm --save-dev webpack
npm -D webpack
复制代码
npm中采用Unix参数风格表示简写,这就是一种很恰当的方式,那么前面示例中的-age按照语义应该改成--age更加合理一点。webpack
NodeJS中的readline模块提供question和prompt方法构建命令行界面,下面是一个简单的问答式的交互界面:git
const readline = require('readline');
const question = ['请输入您的姓名', '请输入您的年龄']
const result = []
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
prompt: `?${question[0]} `
});
rl.prompt();
rl.on('line', (line) => {
result.push(line.trim())
const max = result.length
if (max === question.length) {
rl.close()
}
rl.setPrompt(`?${question[max]} `)
rl.prompt();
}).on('close', () => {
console.log(`谢谢参与问答 *** 姓名: ${result[0]} 年龄: ${result[1]}`);
process.exit(0);
});
复制代码
下面能够尝试实现一个单项选择交互界面:github
const readline = require('readline')
let selected = 0
const choices = ['javascript', 'css', 'html']
let lineCount = 0
const rl = readline.createInterface(process.stdin, process.stdout)
function reader () {
let str = ''
for (let i = 0; i < choices.length; i++) {
lineCount++
str += `${selected === i ? '[X]' : '[ ]'} ${choices[i]}\r\n`
}
process.stdout.write(str)
}
reader()
process.stdin.on('keypress', (s, key) => {
const name = key.name
const max = choices.length
if (name === 'up' && selected > 0) {
selected--
} else if (name === 'down' && selected < max - 1) {
selected++
} else if (name === 'down' && selected === max - 1) {
selected = 0
} else if (name === 'up' && selected === 0) {
selected = max - 1
} else {
return true
}
// 移动光标至起始位置,确保后续输入覆盖当前内容
readline.moveCursor(process.stdout, 0, -lineCount)
lineCount -= choices.length
reader()
})
rl.on('line', () => {
console.log(`you choose ${choices[selected]}`)
process.exit(0)
}).on('close', () => {
rl.close()
})
复制代码
为了有效的区别命令行界面中信息的差别性,咱们能够为这里输出信息添加适当的样式。web
这里介绍一下字符串添加样式的语法:
\x1b[背景颜色编号;字体颜色编号m
复制代码
每条样式都要以\x1b[开头:
// \x1b[0m 清除样式
process.stdout.write('\x1b[44;37m OK \x1b[0m just do it\n')
复制代码
接下来就是自定义Node命令,首先须要建立一个命令执行的文件:
// hello.js 首行须要指定脚本的解释程序
#!/usr/bin/env node
console.log('hello')
复制代码
再利用package.json中的bin配置:
{
"bin": {
"hello": "./hello.js"
},
}
复制代码
执行npm的link命令:
npm link
# 输入自定义命令
hello
# 输出 hello
复制代码
上面介绍了开发Node-CLI时所须要的一些基本知识,可是对于用过诸如webpack-cli、vue-cli工具的你可能会发现这些优秀的CLI工具还具备:
那么下面这些成熟的框架会给你很大的帮助: