inquirer用法
const inquirer = require('inquirer');
inquirer
.prompt([
{
type: 'input',
name: 'youName',
message: 'your name',
validate: function(v) {
return typeof v === 'string';
},
transformer: function(v) {
return v + `(input your name)`;
},
filter: function(v) {
return `name[${v}]`
}
},
{
type: 'number',
name: 'youNumber',
message: 'your number'
},
{
type: 'password',
name: 'password',
message: 'your password'
},
{
type: 'confirm',
name: 'yourConfirm',
message: 'your confirm',
default: false
},
{
type: 'confirm',
name: 'yourConfirm',
message: 'your confirm'
},
{
type: 'list',
name: 'yourChoice',
message: 'your choice list',
default: 0,
choices: [
{ value: 1, name: 'sam' },
{ value: 2, name: 'shuangyue' },
{ value: 3, name: 'zhangxuan' }
]
},
{
type: 'rawlist',
name: 'yourChoice',
message: 'your choice list',
default: 0,
choices: [
{ value: 1, name: 'sam' },
{ value: 2, name: 'shuangyue' },
{ value: 3, name: 'zhangxuan' }
]
},
{
type: 'expand',
name: 'expand',
message: 'your expand',
default: 'red',
choices: [
{ key: 'R', value: 'red' },
{ key: 'G', value: 'green' },
{ key: 'B', value: 'blue' }
]
},
{
type: 'checkbox',
name: 'checkbox',
message: 'your checkbox',
default: 0,
choices: [
{ value: 1, name: 'sam' },
{ value: 2, name: 'shuangyue' },
{ value: 3, name: 'zhangxuan' }
]
},
{
type: 'editor',
name: 'editor',
message: 'your editor'
},
])
.then(answers => {
console.log(answers)
})
.catch(error => {
if(error.isTtyError) {
// Prompt couldn't be rendered in the current environment
} else {
// Something else when wrong
}
});
windows修改域名映射关系
找到C:\Windows\System32\drivers\etc目录 打开hosts文件修改映射关系 127.0.0.1 www.why.com 浏览器输入www.why.com:7001/project/template
手写readline核心实现
function stepread(cb) {
function onKeypress(s) {
output.write(s);
line += s;
switch (s) {
case '\r':
input.pause();
cb(line);
break;
}
}
const input = process.stdin;
const output = process.stdout;
let line = '';
emitKeypressEvents(input);
input.on('keypress', onKeypress);
input.setRawMode(true);
input.resume();
}
function emitKeypressEvents(input) {
function onData(chunk) {
g.next(chunk.toString());
}
const g = emitKeys(input);
g.next();
input.on('data', onData);
}
function* emitKeys(input) {
while (true) {
let ch = yield;
input.emit('keypress', ch);
}
}
stepread(function (answer) {
console.log('answer:' + answer);
});
ansi-escape
ANSI escape sequences are a standard for in-band signaling to control the cursor location, color, and other options on video text terminals and terminal emulators.
console.log(`\x1B[93m\x1B[4m%s\x1B[0m`, 'your name');
rxjs
RxJS是ReactiveX编程理念的JavaScript版本。ReactiveX来自微软,它是一种针对异步数据流的编程。简单来说,它将一切数据,包括HTTP请求,DOM事件或者普通数据等包装成流的形式,然后用强大丰富的操作符对流进行处理,使你能以同步编程的方式处理异步数据,并组合不同的操作符来轻松优雅的实现你所需要的功能。 类似Promise
const { range } = require('rxjs');
const { map, filter } = require('rxjs/operators');
const pipe = range(1, 200).pipe(
filter(x => x % 2 === 1),
map(x => x + x),
filter(x => x % 3 === 0),
filter(x => x % 6 === 0),
filter(x => x % 9 === 0)
)
pipe.subscribe(x => console.log(x));
手写命令行交互列表
const EventEmitter = require('events');
const MuteStream = require('mute-stream');
const readline = require('readline');
const {fromEvent} = require('rxjs');
var cliCursor = require('cli-cursor');
const ansiEscapes = require('ansi-escapes');
const option = {
type: 'list',
name: 'userList',
message: '请选择姓名',
choices: [
{ value: 'sam', name: 'sam'},
{ value: 'sy', name: 'shuangyue'},
{ value: 'zx', name: 'zhangxuan'}
]
}
class List extends EventEmitter {
constructor(list) {
super();
this.type = list.type;
this.name = list.name;
this.message = list.message;
this.choices = list.choices;
this.input = process.stdin;
const ms = new MuteStream();
ms.pipe(process.stdout);
this.output = ms;
this.rl = readline.createInterface({
input: this.input,
output: this.output
})
this.selected = 0;
this.height = 0;
this.keypress = fromEvent(this.rl.input, 'keypress').forEach(this.onkeypress);
this.haveSelected = false;
}
onkeypress= (keys) => {
const key = keys[1];
switch (key.name) {
case 'down':
if (this.selected === this.choices.length - 1) {
this.selected = 0;
} else {
this.selected++;
}
this.render();
break;
case 'up':
if (this.selected === 0) {
this.selected = this.choices.length - 1;
} else {
this.selected--;
}
this.render();
break;
case 'return':
this.haveSelected = true;
this.render();
this.close();
// 派发给程序开发者的
this.emit('exit', this.choices[this.selected]);
break;
default:
break;
}
}
render() {
this.output.unmute();
this.clean();
this.output.write(this.getContent());
this.output.mute();
}
getContent() {
if (!this.haveSelected) {
let content = '\x1B[32m?\x1B[39m \x1B[1m' + this.message + '\x1B[22m\x1B[0m \x1B[0m\x1B[2m(Use arrow keys)\x1B[22m\n';
this.choices.forEach((choice, index) => {
if (index === this.selected) {
if (index === this.choices.length - 1) {
content += '\x1B[36m> ' + choice.name + '\x1B[39m\n';
} else {
content += '\x1B[36m> ' + choice.name + '\x1B[39m\n';
}
} else {
if (index === this.choices.length - 1) { // 最后一行 不要加\n
content += ' ' + choice.name + '\n';
} else { // 不是最后一行,添加\n
content += ' ' + choice.name + '\n';
}
}
})
// 空行 询问标题占两行
this.height = this.choices.length + 2;
return content;
} else {
const name = this.choices[this.selected].name;
return '\x1B[32m?\x1B[39m \x1B[1m' + this.message + '\x1B[22m\x1B[0m \x1B[36m' + name + '\x1B[39m\x1B[0m \n';
}
}
clean() {
const emptyLines = ansiEscapes.eraseLines(this.height);
this.output.write(emptyLines);
}
close() {
this.output.unmute();
this.rl.output.end();
this.rl.pause();
this.rl.close();
}
}
function prompt(option) {
return new Promise((resolve, reject) => {
try {
const list = new List(option);
list.render();
list.on('exit', s => resolve(s));
} catch(e) {
reject(e);
}
})
}
prompt(option).then((result) => {
console.log(result);
}
);