UNPKG

create-common-library

Version:

CLI for creating reusable, modern common libraries using `create-react-library`, `react-styleguidist` or `storybook`.

190 lines (149 loc) 4.42 kB
#!/usr/bin/env node import * as inquirer from "inquirer"; import * as fs from "fs"; import * as path from "path"; import * as shell from "shelljs"; import * as template from "./utils/template"; import chalk from "chalk"; import * as yargs from "yargs"; const CHOICES = fs.readdirSync(path.join(__dirname, "../templates")); const QUESTIONS = [ { name: "template", type: "list", message: "What library template would you like to generate?", choices: CHOICES, when: () => !yargs.argv["template"], }, { name: "name", type: "input", message: "Project name:", when: () => !yargs.argv["name"], validate: (input: string) => { if (/^([A-Za-z\-\_\d])+$/.test(input)) return true; else return "Project name may only include letters, numbers, underscores and hashes."; }, }, ]; const CURR_DIR = process.cwd(); export interface TemplateConfig { files?: string[]; postMessage?: string; } export interface CliOptions { projectName: string; templateName: string; templatePath: string; tartgetPath: string; config: TemplateConfig; } inquirer.prompt(QUESTIONS).then((answers) => { answers = Object.assign({}, answers, yargs.argv); const projectChoice = answers["template"]; const projectName = answers["name"]; const templatePath = path.join(__dirname, "templates", projectChoice); const tartgetPath = path.join(CURR_DIR, projectName); const templateConfig = getTemplateConfig(templatePath); const options: CliOptions = { projectName, templateName: projectChoice, templatePath, tartgetPath, config: templateConfig, }; if (!createProject(tartgetPath)) { return; } createDirectoryContents(templatePath, projectName, templateConfig); if (!postProcess(options)) { return; } showMessage(options); }); function showMessage(options: CliOptions) { console.log(""); console.log(chalk.green("Done.")); console.log(chalk.green(`Go into the project: cd ${options.projectName}`)); const message = options.config.postMessage; if (message) { console.log(""); console.log(chalk.yellow(message)); console.log(""); } } function getTemplateConfig(templatePath: string): TemplateConfig { const configPath = path.join(templatePath, ".template.json"); if (!fs.existsSync(configPath)) return {}; const templateConfigContent = fs.readFileSync(configPath); if (templateConfigContent) { return JSON.parse(templateConfigContent.toString()); } return {}; } function createProject(projectPath: string) { if (fs.existsSync(projectPath)) { console.log( chalk.red(`Folder ${projectPath} exists. Delete or use another name.`) ); return false; } fs.mkdirSync(projectPath); return true; } function postProcess(options: CliOptions) { if (isNode(options)) { return postProcessNode(options); } return true; } function isNode(options: CliOptions) { return fs.existsSync(path.join(options.templatePath, "package.json")); } function postProcessNode(options: CliOptions) { shell.cd(options.tartgetPath); let cmd = ""; if (shell.which("yarn")) { cmd = "yarn"; } else if (shell.which("npm")) { cmd = "npm install"; } if (cmd) { const result = shell.exec(cmd); if (result.code !== 0) { return false; } } else { console.log(chalk.red("No yarn or npm found. Cannot run installation.")); } return true; } const SKIP_FILES = ["node_modules", ".template.json"]; function createDirectoryContents( templatePath: string, projectName: string, config: TemplateConfig ) { const filesToCreate = fs.readdirSync(templatePath); filesToCreate.forEach((file) => { const origFilePath = path.join(templatePath, file); // get stats about the current file const stats = fs.statSync(origFilePath); if (SKIP_FILES.indexOf(file) > -1) return; if (stats.isFile()) { let contents = fs.readFileSync(origFilePath, "utf8"); contents = template.render(contents, { projectName }); const writePath = path.join(CURR_DIR, projectName, file); fs.writeFileSync(writePath, contents, "utf8"); } else if (stats.isDirectory()) { fs.mkdirSync(path.join(CURR_DIR, projectName, file)); // recursive call createDirectoryContents( path.join(templatePath, file), path.join(projectName, file), config ); } }); }