process.env.NODE_PATH = __dirname + "/../node_modules/"; import program from "commander"; import chalk from "chalk"; import envinfo from "envinfo"; import didYouMean from "didyoumean"; import minimist from "minimist"; didYouMean.threshold = 0.6; import packageJson from "./../package.json"; import { enhanceErrorMessages } from "./utils/enhanceErrorMessages"; import create from "./lib/create"; import { CliOptions } from "./types/"; function suggestCommands(unknownCommand: string): void { const availableCommands = program.commands.map((cmd: any) => { return cmd._name; }); const suggestion: string | string[] = didYouMean(unknownCommand, availableCommands); if (suggestion) { console.log(` ` + chalk.red(`Did you mean ${chalk.yellow((suggestion as any) as TemplateStringsArray)}?`)); } } function camelize(str: string): string { return str.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : "")); } /** * 解析 cli options * * @returns {import("./../types").CliOptions} */ function cleanArgs(cmd: any): CliOptions { const args = {}; cmd.options.forEach((o: any) => { const key = camelize(o.long.replace(/^--/, "")); if (typeof cmd[key] !== "function" && typeof cmd[key] !== "undefined") { args[key] = cmd[key]; } }); return args; } const programName = "luban init"; program.version(packageJson.version).usage(" [options]"); program .command("init ") .description("init a new project") .option("-r, --registry ", "Use specified npm registry when installing dependencies (only for npm)") .option("-s, --skipGit", "Skip git initialization") .option("-g, --git [message]", "Force git initialization with initial commit message") .option("-f, --force", "Overwrite target directory if it exists") .action((name, cmd) => { if (name === "") { console.error("Please specify the project directory:"); console.log(` ${chalk.cyan(programName)} ${chalk.green("")}`); console.log(); console.log("For example:"); console.log(` ${chalk.cyan(programName)} ${chalk.green("my-react-app")}`); console.log(); console.log(`Run ${chalk.cyan(`${programName} --help`)} to see all options.`); process.exit(1); } 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.", ), ); } if (process.argv.includes("-g") || process.argv.includes("--git")) { options.forceGit = true; } create(name, options); }); program .command("info") .description("print debugging information about your environment") .action(() => { console.log(chalk.bold("\nEnvironment Info:")); envinfo .run( { System: ["OS", "CPU"], Binaries: ["Node", "npm"], Browsers: ["Chrome", "Edge", "Firefox", "Safari"], npmPackages: ["typescript", "react", "react-dom"], npmGlobalPackages: ["luban-react-cli"], }, { showNotFound: true, duplicates: true, fullTree: true, }, ) .then(console.log); }); program.arguments("").action((cmd) => { program.outputHelp(); console.log(` ` + chalk.red(`Unknown command ${chalk.yellow(cmd)}.`)); console.log(); suggestCommands(cmd); }); program.on("--help", () => { console.log(` Only ${chalk.green("")} is required.`); console.log(); console.log(); }); enhanceErrorMessages("missingArgument", (argName: string) => { return `Missing required argument ${chalk.yellow(`<${argName}>`)}.`; }); enhanceErrorMessages("unknownOption", (optionName: string) => { return `Unknown option ${chalk.yellow(optionName)}.`; }); enhanceErrorMessages("optionMissingArgument", (option: any, flag: any) => { return ( `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(); }