zoro-cli
Version:
https://github.com/vuejs/vue-cli
195 lines (174 loc) • 5.09 kB
JavaScript
const { log, info, warn, error, success } = require('zoro-cli-util/logger')
const {
getPkgVersion,
packInstallPkgGlobalCmd,
installPkgGlobal,
} = require('zoro-cli-util/pkg')
const path = require('path')
const chalk = require('chalk')
const semver = require('semver')
const program = require('commander')
const { merge } = require('lodash')
const inquirer = require('inquirer')
const currPkgPath = '../package.json'
/* eslint-disable import/no-dynamic-require */
const currPkg = require(currPkgPath)
/* eslint-enable import/no-dynamic-require */
let cliPkg = currPkg
const cmdConfig = {
init: {
docSite: '',
},
}
function loadPkg(pkgPath) {
if (pkgPath) {
if (pkgPath.indexOf('package.json') === -1) {
pkgPath = path.join(pkgPath, 'package.json')
}
/* eslint-disable import/no-dynamic-require */
cliPkg = require(pkgPath)
/* eslint-enable import/no-dynamic-require */
}
}
function config(options = {}) {
const { pkgPath, cmd } = options
loadPkg(pkgPath)
merge(cmdConfig, cmd)
}
// commander passes the Command object itself as options,
// extract only actual options into a fresh object.
function cleanArgs(cmd) {
const args = {
cliPkg,
}
cmd.options.forEach(o => {
const key = o.long.replace(/^--/, '')
// if an option is not present and Command has a method with the same name
// it should not be copied
if (typeof cmd[key] !== 'function') {
args[key] = cmd[key]
}
})
return merge(cmdConfig[cmd._name], args)
}
async function run() {
// ref https://github.com/vuejs/vue-cli/blob/v3.0.0-beta.6/packages/%40vue/cli/bin/vue.js
// check node version
const requiredVersion = '>8.2.0'
if (!semver.satisfies(process.version, requiredVersion)) {
warn(
`You are using Node ${process.version}, but this version of cli ` +
`requires Node ${requiredVersion}.\nPlease upgrade your Node version.`,
)
// process.exit(1);
}
// check pkg update
const latest = await getPkgVersion(cliPkg)
const current = cliPkg.version
if (semver.gt(latest, current)) {
log(
chalk.green(`
──────────────────────────${'─'.repeat(latest.length)}──
✨ Update available: ${latest} ✨
──────────────────────────${'─'.repeat(latest.length)}──\n\n`),
)
const { update } = await inquirer.prompt([
{
type: 'list',
name: 'update',
message: 'update available, you should update now',
choices: [
{
name: 'yes',
value: true,
},
{
name: 'no',
value: false,
},
],
},
])
if (update) {
await installPkgGlobal({
name: cliPkg.name,
version: latest,
})
log()
success(`${cliPkg.name} is updated, please re-run your last command`)
log()
warn(
`if somehow the auto-update doesn't work for you,
- you can update manually by run command like: ${packInstallPkgGlobalCmd({
name: cliPkg.name,
version: latest,
})}
- or you can always contact the author
`,
)
log()
process.exit()
}
}
program.version(cliPkg.version).usage('<command> [options]')
function collect(val, memo) {
memo.push(val)
return memo
}
program
.command('init')
.description('init project')
.option('--npmClient [npm]', 'npm client')
.option('--pluginDirs [pluginDirs]', 'plugin dirs', collect, [])
.option('--pnp', 'use Yarn pnp')
.action(cmd => {
const options = cleanArgs(cmd)
require('./init')(options)
})
// output help information on unknown commands
program.arguments('<command>').action(cmd => {
program.outputHelp()
error(` ' + Unknown command ${chalk.yellow(cmd)}.`)
})
program.commands.forEach(c =>
c.on('--help', () => {
const options = cleanArgs(c)
if (options.docSite) {
info(' 文档: ' + options.docSite)
}
log()
}),
)
// enhance common error messages
const enhanceErrorMessages = (methodName, logFunc) => {
program.Command.prototype[
methodName
] = function enhanceErrorMessagesForCommand(...args) {
if (methodName === 'unknownOption' && this._allowUnknownOption) {
return
}
this.outputHelp()
log(' ' + chalk.red(logFunc(...args)))
process.exit(1)
}
}
enhanceErrorMessages(
'missingArgument',
argName => `Missing required argument ${chalk.yellow(`<${argName}>`)}.`,
)
enhanceErrorMessages(
'unknownOption',
optionName => `Unknown option ${chalk.yellow(optionName)}.`,
)
enhanceErrorMessages(
'optionMissingArgument',
(option, flag) =>
`Missing required argument for option ${chalk.yellow(option.flags)}` +
(flag ? `, got ${chalk.yellow(flag)}` : ''),
)
program.parse(process.argv)
if (!process.argv.slice(2).length) {
program.outputHelp()
}
}
module.exports = { config, run }