UNPKG

create-yard-app

Version:

CLI tool to create indepedent ops portal apps

176 lines (157 loc) 5.8 kB
#!/usr/bin/env node import validateNPMPackage from 'validate-npm-package-name' import chalk from 'chalk' import commander from 'commander' import fsExtras from 'fs-extra' import dns from 'dns' import path from 'path' import spawn from 'cross-spawn' import packageJSON from '../package.json' function validateAppName(appName) { const validationResult = validateNPMPackage(appName) if (!validationResult.validForNewPackages) { console.error(`Could not create a App called ${chalk.red(appName)} because of npm naming restrictions`) console.error(validationResult.errors) console.warn(validationResult.warnings) process.exit(1) } } function checkIfOnline() { return new Promise((resolve) => { dns.resolve('registry.yarnpkg.com', (err) => { resolve(err === null) }) }) } function isSafeToCreateProjectIn(root, name) { const validFiles = ['.DS_Store', 'Thumbs.db', '.git', '.gitignore', '.idea', 'README.md', 'LICENSE', 'web.iml'] const isSafe = fsExtras.readdirSync(root).every(function(file) { return validFiles.indexOf(file) >= 0 }) if (!isSafe) { console.log('The directory ' + chalk.green(name) + ' contains files that could conflict.') console.log('Try using a new directory name.') process.exit(1) } } function install(depedencies = [], isOnline) { return new Promise((resolve, reject) => { const command = 'yarnpkg' const args = ['add', '--exact'].concat(depedencies) if (!isOnline) { console.log(chalk.yellow('You appear to be offline')) console.log(chalk.yellow('Falling back to yarn local cache')) console.log() } spawn(command, args, { stdio: 'inherit' }).on('close', (code) => { if (code !== 0) { reject({ command: `${command} ${args.join(' ')}`, }) return } resolve() }) }) } function writeBasicPackageJSON(name, root) { const packageJSONContents = { name, version: '0.1.0', private: true, } fsExtras.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJSONContents, null, 2)) } function initProject(root, packageName, name) { const scriptsPath = path.resolve(root, 'node_modules', packageName, 'dist', 'scripts', 'init.js') const init = require(scriptsPath).default init(root, name) } function fixDependencies(packageName) { const packagePath = path.join(process.cwd(), 'package.json') const packageJson = require(packagePath) if (typeof packageJson.dependencies === 'undefined') { console.error(chalk.red('Missing dependencies in package.json')) process.exit(1) } const packageVersion = packageJson.dependencies[packageName] if (typeof packageVersion === 'undefined') { console.error(chalk.red('Unable to find ' + packageName + ' in package.json')) process.exit(1) } packageJson.devDependencies = packageJson.devDependencies || {} packageJson.devDependencies[packageName] = packageVersion delete packageJson.dependencies[packageName] fsExtras.writeFileSync(packagePath, JSON.stringify(packageJson, null, 2)) } function installYardScripts(root, name) { const packageToBeInstalled = 'g2-ops-scripts' checkIfOnline() .then((isOnline) => { // Online console.log(`Installing ${chalk.cyan(packageToBeInstalled)} ...`) return install([packageToBeInstalled], isOnline) }) .then(() => { fixDependencies(packageToBeInstalled) initProject(root, packageToBeInstalled) }) .catch((reason) => { console.log() console.log('Aborting installation.') if (reason.command) { console.log(' ' + chalk.cyan(reason.command), 'has failed.') } else { console.log(chalk.red('Unexpected error. Please report it as a bug:')) console.log(reason) } console.log() // On 'exit' we will delete these files from target directory. const knownGeneratedFiles = ['package.json', 'npm-debug.log', 'yarn-error.log', 'yarn-debug.log', 'node_modules'] const currentFiles = fsExtras.readdirSync(path.join(root)) currentFiles.forEach(function(file) { knownGeneratedFiles.forEach(function(fileToMatch) { // This will catch `(npm-debug|yarn-error|yarn-debug).log*` files // and the rest of knownGeneratedFiles. if ((fileToMatch.match(/.log/g) && file.indexOf(fileToMatch) === 0) || file === fileToMatch) { console.log('Deleting generated file...', chalk.cyan(file)) fsExtras.removeSync(path.join(root, file)) } }) }) const remainingFiles = fsExtras.readdirSync(path.join(root)) if (!remainingFiles.length) { // Delete target folder if empty console.log('Deleting', chalk.cyan(appName + '/'), 'from', chalk.cyan(path.resolve(root, '..'))) process.chdir(path.resolve(root, '..')) fsExtras.removeSync(path.join(root)) } console.log('Done.') process.exit(1) }) } function createProject(name) { validateAppName(name) const root = path.resolve(name) const appName = path.basename(root) // Here we have valid app name fsExtras.ensureDirSync(name) // Create app directory if you don't have a directory isSafeToCreateProjectIn(root, name) // it is safe to create project writeBasicPackageJSON(name, root) process.chdir(root) installYardScripts(root, name) // TODO: Copy Template to the destination // TODO: Install all depedencies declared in template } let appName = '' // Reading in Command Line arguments new commander.Command(packageJSON.name) .version(packageJSON.version) .arguments('<project-directory>') .usage(`${chalk.green('<project-directory>')} [options]`) .action((name) => { appName = name }) .parse(process.argv) createProject(appName)