@watone/wt-cli
Version:
watone tools
351 lines (301 loc) • 8.4 kB
JavaScript
/*
* @describe: 用户选择
* @Author: superDragon
* @Date: 2019-08-30 11:21:35
* @LastEditors: superDragon
* @LastEditTime: 2019-08-30 11:22:14
*/
/**
* @file 通过 Schema 生成可以让用户输入的 Question Form
*/
const exec = require('mz/child_process').exec;
const fs = require('fs-extra');
const os = require('os');
const inquirer = require('inquirer');
const path = require('path');
const locals = require('../../locals')();
const log = require('../../lib/utils/log');
;
/**
* 获取当前用户的 git 账号信息
*
* @return {Promise} promise 对象
*/
async function getGitInfo () {
let author;
let email;
try {
// 尝试从 git 配置中获取
author = await exec('git config --get user.name');
email = await exec('git config --get user.email');
}
catch (e) {
}
author = author && author[0] && author[0].toString().trim();
email = email && email[0] && email[0].toString().trim();
return { author, email };
}
/**
* 询问 input 类型的参数
*
* @param {string} key 参数的 key
* @param {Object} schema schema 内容
* @param {Object} params 当前已有的参数
* @return {Object} question 需要的参数
*/
async function questionInput (key, schema, params) {
let con = schema[key];
let { name, invalidate } = con;
let defaultVal = con.default;
// 语言 locals - zh_CN
let itemLocals = con.locals && con.locals[locals.LANG];
if (itemLocals) {
// locals - zh_CN - name
name = itemLocals.name || name;
// 模板类型
defaultVal = itemLocals.default || defaultVal;
invalidate = itemLocals.invalidate || invalidate;
}
con.validate = () => !!1;
// 如果输入项是 author 或者 email 的,尝试去 git config 中拿默认内容
if (key === 'author' || key === 'email') {
let userInfo = await getGitInfo();
defaultVal = userInfo[key] || con.default;
}
if (key === 'dirPath') {
defaultVal = path.resolve(process.cwd(), con.default || '');
con.validate = value => {
let nowPath = path.resolve(process.cwd(), value || '');
if (!fs.existsSync(nowPath)) {
return invalidate || locals.INPUT_INVALID;
}
else {
}
return true;
}
}
if (con.regExp) {
let reg = new RegExp(con.regExp);
con.validate = value => {
if (!reg.test(value)) {
return invalidate || locals.INPUT_INVALID;
}
return true;
}
}
return {
// 密码
'type': con.type === 'password' ? 'password' : 'input',
'name': key,
// 提示信息
'message': `${locals.PLEASE_INPUT}${name}: `,
// 默认值
'default': defaultVal,
// 验证
'validate': con.validate
}
}
/**
* 询问 boolean 类型的参数
*
* @param {string} key 参数的 key
* @param {Object} schema schema 内容
* @param {Object} params 当前已有的参数
* @return {Object} question 需要的参数
*/
async function questionYesOrNo (key, schema, params) {
let con = schema[key];
// 名称
let name = con.name;
// 语言
let itemLocals = con.locals && con.locals[locals.LANG];
if (itemLocals) {
name = itemLocals.name || name;
}
return {
'type': 'confirm',
'name': key,
'default': false,
'message': `${name}? :`
}
}
/**
* 询问 list 类型的参数 (多选或者单选)
*
* @param {string} key 参数的 key
* @param {Object} schema schema 内容
* @param {Object} params 当前已有的参数
* @return {Object} question 需要的参数
*/
function questionList (key, schema, params) {
let con = schema[key];
// 来源列表
let sourceLish = [];
// 选择列表
let choiceList = [];
let text = '';
let valueList = [];
let listName = con.name;
// 模板类型
let listLocals = con.locals && con.locals[locals.LANG];
if (listLocals) {
listName = listLocals.name;
}
// 依赖
if (!con.dependence) {
sourceLish = con.list;
}
// 层级
else if (con.depLevel > 0) {
// 表示是级联的操作
let dependence = con.dependence;
// 类型 template
let ref = con.ref;
let depList = schema[dependence].list;
let depValue = params[dependence] || schema[dependence].list[0];
depList.forEach((depItem) => {
if (depItem.value === depValue) {
sourceLish = (depItem.subList && depItem.subList[ref]);
}
});
}
sourceLish.forEach((item, index) => {
let url = '';
let { desc, name } = item;
let itemLocals = item.locals && item.locals[locals.LANG];
if (itemLocals) {
desc = itemLocals.desc || desc;
name = itemLocals.name || name;
}
desc = log.chalk.gray('\n ' + desc);
choiceList.push({
value: item.value,
name: `${name}${desc}${url}`,
short: item.value
});
valueList.push(item.value);
text += ''
+ log.chalk.blue('\n [' + log.chalk.yellow(index + 1) + '] ' + name)
+ desc;
});
// 如果是 windows 下的 git bash 环境,由于没有交互 GUI,所以就采用文本输入的方式来解决
if (os.platform() === 'win32' && process.env.ORIGINAL_PATH) {
return {
'type': 'input',
'name': key,
'message': locals.PLEASE_INPUT_NUM_DESC + ' ' + listName + ':' + text
+ '\n' + log.chalk.green('?') + ' ' + locals.PLEASE_INPUT_NUM + ':',
'default': 1,
'valueList': valueList,
// 验证
'validate' () {
if (!/\d+/.test(value) || +value > valueList.length || +value <= 0) {
return locals.PLEASE_INPUT_RIGHR_NUM;
}
return true;
}
};
}
return {
'type': 'list',
'name': key,
'message': `${locals.PLEASE_SELECT}${listName} (${log.chalk.green(locals.PLEASE_SELECT_DESC)}):`,
'choices': choiceList,
'default': choiceList[0].value || '',
'checked': !!con.checkbox,
'pageSize': 1000
}
}
/**
* 询问 checkbox-plus 类型的参数 (多选或者单选)
*
* @param {string} key 参数的 key
* @param {Object} schema schema 内容
* @param {Object} params 当前已有的参数
* @return {Object} question 需要的参数
*/
function questionCheckboxPlus (key, schema, params) {
let con = schema[key];
// 来源列表
let sourceLish = con.list;
// 选择列表
let choiceList = [];
sourceLish.forEach((item, index) => {
let { name } = item;
let itemLocals = item.locals && item.locals[locals.LANG];
if (itemLocals) {
name = itemLocals.name || name;
}
choiceList.push({
value: item.value,
name: name,
checked: item.checked
});
});
return {
'type': con.type,
'name': key,
'message': con.name,
'choices': choiceList
}
}
/**
* 解析schme, 生成 form 表单
*
* @param {Object} schema 传入的 schema 规则
* @return {Object} 获取的 form 参数
*/
module.exports = async function (schema) {
let params = {};
if (schema.key) {
let opts = {};
let data = {};
opts = await questionCheckboxPlus(schema.key,
{
[schema.key]: schema
}, params);
data = await inquirer.prompt([opts]).then(function (answers) {
return {
[schema.key]: answers[schema.key]
};
});
params = Object.assign({}, params, data);
return params
}
else {
for (let key of Object.keys(schema)) {
let con = schema[key];
let type = con.type;
let opts = {};
let data = {};
switch (type) {
case 'string':
case 'number':
case 'password':
// 输入密码
opts = await questionInput(key, schema, params);
break;
case 'boolean':
// 确认
opts = await questionYesOrNo(key, schema, params);
break;
case 'list':
// 列表
opts = await questionList(key, schema, params);
break;
}
// 如果 list 只有一个 item 的时候,就不需要用户选择了,直接给定当前的值就行
if (type === 'list' && con.list.length === 1) {
data[key] = con.list[0].value;
}
else if (!con.disable && !con.key) {
data = await inquirer.prompt([opts]);
if (opts.valueList) {
data[key] = opts.valueList[+data[key] - 1];
}
}
params = Object.assign({}, params, data);
}
}
return params;
};