UNPKG

@jdbk/book-cli

Version:

Command line interface for front end project

194 lines (168 loc) 6.49 kB
#!/usr/bin/env node const chalk = require('chalk'); // const execa = require("execa"); const semver = require('semver'); // 语义化版本规范 const leven = require('leven'); // 测量两字符串之间的差异; const program = require('commander'); const slash = require('slash'); // 转换 Windows 反斜杠路径转换为正斜杠路径 \ => / // const minimist = require('minimist'); // 解析命令行选项 const requiredVersion = require('../package.json').engines.node; // 检查Node版本 function checkNodeVersion(wanted, id) { if (!semver.satisfies(process.version, wanted, { includePrerelease: true, })) { console.log(chalk.red( `You are using Node ${process.version}, but this version of ${id } requires Node ${wanted}.\nPlease upgrade your Node version.`, )); process.exit(1); } } checkNodeVersion(requiredVersion, '@book/cli'); const EOL_NODE_MAJORS = ['8.x', '9.x', '11.x', '13.x']; // eslint-disable-next-line no-restricted-syntax for (const major of EOL_NODE_MAJORS) { if (semver.satisfies(process.version, major)) { console.log( chalk.red( // eslint-disable-next-line no-useless-escape `You are using Node ${process.version}.\n Node.js ${major} has already reached end-of-life and will not be supported in future major releases.\n It\'s strongly recommended to use an active LTS version instead.`, ), ); } } // 创建测试存储库时进入调试模式 if (slash(process.cwd()).indexOf('/packages/test') > 0) { process.env.BOOK_CLI_DEBUG = true; } function camelize(str) { return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : '')); } // 将命令对象本身作为选项传递,只将实际选项提取到新对象中。 function cleanArgs(cmd) { const args = {}; cmd.options.forEach((o) => { const key = camelize(o.long.replace(/^--/, '')); // 如果选项不存在且命令具有同名的方法,则不复制 if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') { args[key] = cmd[key]; } }); return args; } // 指令建议 function suggestCommands(unknownCommand) { // eslint-disable-next-line no-underscore-dangle const availableCommands = program.commands.map((cmd) => cmd._name); let suggestion; availableCommands.forEach((cmd) => { const isBestMatch = leven(cmd, unknownCommand) < leven(suggestion || '', unknownCommand); if (leven(cmd, unknownCommand) < 3 && isBestMatch) { suggestion = cmd; } }); if (suggestion) { console.log(` ${chalk.red(`Did you mean ${chalk.yellow(suggestion)}?`)}`); } } /** * init:初始化项目 * list: 展示模板列表 * create:创建一个模板/generator * add:添加模板 * */ // 基础信息 program .version(require('../package.json').version) .usage('<command> [options]'); // list: 展示模板列表 program .command('list') .description('look all template list') // .option('-d, --default', 'Skip prompts and use default preset') .action(() => { // eslint-disable-next-line global-require require('../lib/list'); }); // init:初始化项目 program .command('init <template-name> [project-name]') .description('init a new project powered by ') // .option('-d, --default', 'Skip prompts and use default preset') .action((tplName, projectName = '', cmd) => { // console.log('tplName=', tplName); // console.log('projectName=', projectName); const options = cleanArgs(cmd); // console.log('cmd=', options); // eslint-disable-next-line global-require require('../lib/init')(tplName, projectName, options); }); // create:创建一个模板/generator program .command('init <app-name>') .description('create a new project powered by vue-cli-service') .option('-p, --preset <presetName>', 'Skip prompts and use saved or remote preset') .option('-d, --default', 'Skip prompts and use default preset') .option('-i, --inlinePreset <json>', 'Skip prompts and use inline JSON string as preset') .option('-m, --packageManager <command>', 'Use specified npm client when installing dependencies') .option('-r, --registry <url>', 'Use specified npm registry when installing dependencies (only for npm)') .option('-g, --git [message]', 'Force git initialization with initial commit message') .option('-n, --no-git', 'Skip git initialization') .option('-f, --force', 'Overwrite target directory if it exists') .option('--merge', 'Merge target directory if it exists') .option('-c, --clone', 'Use git clone when fetching remote preset') .option('-x, --proxy <proxyUrl>', 'Use specified proxy when creating project') .option('-b, --bare', 'Scaffold project without beginner instructions') .option('--skipGetStarted', 'Skip displaying "Get started" instructions') .action((name, cmd) => { const options = cleanArgs(cmd); // if (minimist(process.argv.slice(3))._.length > 1) { // console.log(chalk.yellow('\n Info: You provided more than one argument. The first one will be used as the app\'s name, the rest are ignored.')); // } // --git使commander默认git为true if (process.argv.includes('-g') || process.argv.includes('--git')) { options.forceGit = true; } // eslint-disable-next-line global-require require('../lib/create')(name, options); }); // add:添加模板/generator program .command('add <template-name>') .description('add a new template') // .option('-d, --default', 'Skip prompts and use default preset') .action((tplName, cmd) => { const options = cleanArgs(cmd); // eslint-disable-next-line global-require require('../lib/add')(tplName, options); }); // egg: 彩蛋 program .command('egg') .description('this is Easteregg!') .action(() => { // eslint-disable-next-line global-require require('../lib/egg'); }); // 输出未知命令的帮助信息 program .arguments('<command>') .action((cmd) => { program.outputHelp(); console.log(` ${chalk.red(`Unknown command ${chalk.yellow(cmd)}.`)}`); console.log(); suggestCommands(cmd); }); // 在帮助中添加一些有用的信息 program.on('--help', () => { console.log(); console.log(` Run ${chalk.cyan('book <command> --help')} for detailed usage of given command.`); console.log(); }); program.commands.forEach((c) => c.on('--help', () => console.log())); program.parse(process.argv); // 调用 if (!process.argv.slice(2).length) { program.outputHelp(); }