zoro-cli
Version:
https://github.com/vuejs/vue-cli
187 lines (151 loc) • 4.92 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
};