UNPKG

reactatouille

Version:

Reactatouille is a command-line tool to help quickly start and build a new React project, using Redux, Webpack, Gulp (You can add your own tasks, yo!), HMR/Hot Module Reload, Sass (architecture best practices), Jest, Enzyme, popmotion, Redux devtools (bro

239 lines (218 loc) 7.98 kB
#! /usr/bin/env node require('babel-polyfill') var chalk = require('chalk') var figlet = require('figlet') var program = require('commander') var Promise = require('bluebird') var fs = Promise.promisifyAll(require('fs-extra')) var path = require('path') var rootDir = path.resolve(__dirname, '..') var clear = require('cli-clear') var version = require('../package.json').version var modifyRootReducer = require('./helpers/modifyRootReducer') var findAndReplace = require('find-and-replace') // Set options program .version(version) .option('-n, --new-project <Name...>', 'New project', createNewProject) .option('-c, --create-component <Name...>', 'Create Component', createNewComponent) .parse(process.argv) // Default to createNewProject fn if (program.args.length > 0) { var projectName = program.args[0] if (projectName) { // Clear the screen clear() // Show initial screen startScreen() // Create the project createNewProject(projectName) } } function startScreen () { // Show the startup banner console.log( chalk.magenta( figlet.textSync('Reactatouille', { horizontalLayout: 'full' }) ), chalk.yellow.bold('\n' + ' ' + 'Boilerplate CLI' + ' ' + 'v' + version), chalk.yellow('by Punkbit'), '\n', '\n' ) } function createNewProject (projectName) { // Show help if user did not provide a project name if (!projectName) { program.help() } else { var tempateRootDir = rootDir + '/template' fs.stat(tempateRootDir, function (err, stats) { if (err) { console.log('Error found while trying to createNewProject!'); } if (!stats.isDirectory()) { // This isn't a directory! callback(new Error('The template directory does not exist!')); } else { fs.copyAsync(rootDir + '/template', projectName, { clobber: true }) .then(function (err) { // Show the initialization text, white space added to text align console.log(chalk.blue(' ' + 'Creating the project directory `' + projectName + '`...')) console.log('\n') if (err) { return console.error(chalk.red.bold(err)) } else { console.log(chalk.green(' ' + 'Success! Your project boilerplate is ready!')) console.log(chalk.yellow(' ' + 'Remember to `cd ' + projectName + '` and run the `npm install`')) console.log(chalk.yellow(' ' + 'There, you\'ll find the boilerplate README file containing instructions to run the server, build, etc.')) console.log(chalk.green(' ' + 'Happy coding yo!')) console.log('\n') } }) } }) } } function createNewComponent (name) { var originDir = rootDir + '/template/src/js/modules/main' var distDir = findJsPath(name) // find the path for the user if (distDir) { fs.copy(originDir, distDir, { overwrite: true, errorOnExist: true, dereference: true, filter: filterCopy }) .then(function (err) { // Show the initialization text, white space added to text align console.log(chalk.blue(' ' + 'Creating the React component directory `' + name + '`...')) console.log('\n') if (err) { return console.error(chalk.red.bold(err)) } else { modifyRootReducer(name, function () { console.log(chalk.yellow(' ' + 'Oops! Failed to add the import and reducer into `root/src/js/rootReducer.js`')) console.log(chalk.yellow(' ' + 'This is a work in progress, so meanwhile you have to add the component to `root/src/js/rootReducer.js`')) console.log(chalk.yellow(' ' + 'and also modify the name in the `root/src/js/[component]/constants.js`, etc.')) console.log(chalk.yellow(' ' + 'My apologies!')) console.log('\n') }) renameComponentName(name, distDir, function (name) { console.log(chalk.yellow(' ' + 'Updated the new ' + name + ' with the new component name')) }, function (err) { console.log(chalk.yellow(' ' + 'Oops! Failed to rename the component name in the actions, reducers, etc')) }) console.log(chalk.green(' ' + 'The component was created successfully!')) console.log('\n') } }) } else { console.log(chalk.red('Oops! Are you in a Reactatouille Project root, source or js directory?')) console.log('\n') } } function findJsPath (name) { // Known directories var cwd = path.resolve('./') var parentDir = path.resolve('../') var listCwd = getDirectoryFileList(cwd) var listParent = getDirectoryFileList(parentDir) // User may be in the project [ROOT] if (isDir(listCwd, validateRootDir)) { return path.resolve('./src/js/modules/' + name) } // User may be in the dir [root/src] if (isDir(listParent, validateSrcDir)) { return path.resolve('./js/modules/' + name) } // Use may be in the dir [root/src/js] if (isDir(listCwd, validateJsDir)) { return path.resolve('./modules/' + name) } } function getDirectoryFileList (srcpath) { return fs.readdirSync(srcpath) .filter(file => fs.lstatSync(path.join(srcpath, file))) } function isDir (ls, cb) { return typeof cb === 'function' && cb(ls) } function validateRootDir (ls) { try { var pkg = require(path.resolve('./') + '/package.json') || {} var devDependencies = JSON.stringify(pkg.devDependencies).toLowerCase() return ls.indexOf('src') > -1 && ls.indexOf('server.js') > -1 && ls.indexOf('config') > -1 && devDependencies.indexOf('react') > -1 } catch (e) { return false } } function validateSrcDir (ls) { try { var pkg = require(path.resolve('../') + '/package.json') || {} var devDependencies = JSON.stringify(pkg.devDependencies).toLowerCase() var cwd = path.resolve('./') var listCwd = getDirectoryFileList(cwd) return ls.indexOf('src') > -1 && ls.indexOf('server.dev.js') > -1 && ls.indexOf('webpack.dev.config.js') > -1 && listCwd.indexOf('js') > -1 && listCwd.indexOf('index.ejs') > -1 && devDependencies.indexOf('react') > -1 && devDependencies.indexOf('reactatouille') > -1 } catch (e) { return false } } function validateJsDir (ls) { try { var pkg = require(path.resolve('../../') + '/package.json') || {} var devDependencies = JSON.stringify(pkg.devDependencies).toLowerCase() return ls.indexOf('index.js') > -1 && ls.indexOf('root.js') > -1 && ls.indexOf('routes.js') > -1 && devDependencies.indexOf('react') > -1 && devDependencies.indexOf('reactatouille') > -1 } catch (e) { return false } } function renameComponentName (name, path, successCallback, errCallback) { var list = getDirectoryFileList(path) list.forEach(function (v) { if (v.indexOf('.js') > -1) { replace({ src: path + '/' + v, dest: path + '/' + v, name: name, successCallback: successCallback, errCallback: errCallback }) } else { renameComponentName(name, path + '/' + v, successCallback, errCallback) } }) } function replace (params) { findAndReplace .src(params.src) .dest(params.dest) .replace({ 'main/': params.name + '/', "export const NAME = 'main'": `export const NAME = '${params.name}'` }) .complete(function (txt) { // console.log('Finished! Here is the completed text: ' + txt) if (typeof params.successCallback === 'function') { var arr = params.dest.split('/') var fileName = arr[arr.length - 1] params.successCallback(fileName) } }) .error(function (err) { if (typeof params.errCallback === 'function') { params.errCallback(err) } }) } function filterCopy (src, des) { return src.indexOf('node_modules') === -1 }