手写cli
大家好,今天分享一篇手写cli:


index.js
const { program } = require('commander')
const { version } = require('../package.json')
const del = require('del')
const path = require('path')
program.version(version)
// const delFunc = async (name) => {
// const dir = path.resolve('.')
// await del(dir + '/' + name)
// }
// program
// .option('-c, --create','create a project')
// .option('-i, --init <type>','init a project with a name!')
// .option('-d, --delete <file>','delete a file', delFunc)
// //创建子命令
// program
// .command('clone <source> [destination]')
// .option('-i, --inifo', 'clone info')
// .description('clone a repository into a newly created directory')
// .action((source,destination,obj) => {
// console.log('source',source);
// console.log('des',destination)
// console.log(obj);
// })
// console.log('hello world! Hello cli!')
const mapActions = {
init:{
alias:'i',
desc:'create/init a project',
examples:[
'terry init <projectName>',
'terry i <projectName>'
]
},
remove:{
alias:'rm',
desc:'remove files from path',
examples:[
'terry rm -f <filepath>',
'terry rm <filepath>'
]
},
'*':{
alias:'',
desc:'command not found!',
examples:[]
}
}
Reflect.ownKeys(mapActions).forEach(key => {
program
.command(key)
.alias(mapActions[key].alias)
.description(mapActions[key].desc)
.action(() => {
if(key === '*'){
console.log(mapActions[key].desc);
} else {
require(path.resolve(__dirname, `./actions/${key}`))(process.argv.splice(3))
}
})
})
program.parse(process.argv)
const path = require('path')
const fs = require('fs')
const Inquirer = require('inquirer')
const del = require('del')
const axios = require('axios')
const { promisify } = require('util')
const downloadGitRepo = promisify(require('download-git-repo'))
const ncp = promisify(require('ncp'))
const shelljs = require('shelljs')
const ora = require('ora')
const baseUrl = 'https://api.github.com'
const existDir = async(projectName) => {
const dir = path.resolve('.')
const createDir = dir + '/' + projectName
if(fs.existsSync(createDir)){
const result = await Inquirer.prompt({
name:'create dir',
type:'confirm',
message:'Overwrite your existed Directory ?',
default: true
})
if(result){
await del(createDir, { force: true})
fs.mkdirSync(createDir)
return createDir
} else {
console.log('取消了创建目录,停止创建目录!');
process.exit(1)
}
}
fs.mkdirSync(createDir)
return createDir
}
const fetchRepoList = async () => {
const { data } = await axios.get(`${baseUrl}/users/tomic/repos`)
const repoName = data.map(item => item.name).filter(item => /template/.test(item))
return repoName
}
const fetchRepoTags = async (repo) => {
const { data } = await axios.get(`${baseUrl}/repos/tomic/${repo}/tags`)
const tagName = data.map(item => item.name)
return tagName
}
const waitLoading = async (fn, message) => {
const spinner = ora(message)
spinner.start()
const result = await fn()
spinner.succeed()
return result
}
module.exports = async (projectName) => {
//创建目录,如果存在,提示用户是否覆盖
const desk = await existDir(projectName)
console.log(desk);
//拉取github template 选择指定的tag与仓库
const repos = await waitLoading(fetchRepoList,'获取远程仓库列表!')
const { repo } = await Inquirer.prompt({
name:'repo',
type:'list',
message:'Choose the repo needs to download!',
choices: repos
})
const tags = await fetchRepoTags(repo)
const { tag } = await Inquirer.prompt({
name:'tag',
type:'list',
message:'Choose the tag needs to download!',
choices: tags,
})
//下载并安装依赖
let repoUrl = `terry/${repo}`
if(tag){
repoUrl = `terry/${repo}#${tag}`
}
downloadGitRepo(repoUrl,desk + '/tmp')
await ncp(desk + '/tmp',desk)
await del(desk + '/tmp')
shelljs.cd(desk)
shelljs.exec('npm install')
}
浙公网安备 33010602011771号