-
Notifications
You must be signed in to change notification settings - Fork 0
Middleware related store generation Clone espeo-create-react-app while init #14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
b387ca1
ac6cc88
26f2632
d049995
d39a77d
2d1de76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| node_modules | ||
| .DS_Store | ||
| package-lock.json | ||
| package-lock.json | ||
| ./templates/projectTemplate |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,53 +1,49 @@ | ||
| #!/usr/bin/env node | ||
|
|
||
| const program = require('commander'); | ||
| const handlebars = require('handlebars'); | ||
|
|
||
| handlebars.registerHelper('toLowerCase', str => str.toLowerCase()); | ||
| handlebars.registerHelper('toUpperCase', str => str.toUpperCase()); | ||
| handlebars.registerHelper( | ||
| 'capitalize', | ||
| str => str.charAt(0).toUpperCase() + str.slice(1), | ||
| ); | ||
| handlebars.registerHelper('ifEquals', function(arg1, arg2, options) { | ||
| return arg1 == arg2 ? options.fn(this) : options.inverse(this); | ||
| }); | ||
| handlebars.registerHelper('setVar', function(varName, varValue, options) { | ||
| options.data.root[varName] = varValue; | ||
| }); | ||
| const registerHandlebarHelpers = require('../helpers/registerHandlebarHelpers'); | ||
| const cloneProjectTemplate = require('../helpers/cloneProjectTemplate'); | ||
|
|
||
| program | ||
| .version(require('../package').version, '-v, --version') | ||
| .command('generate <type> <name> ') | ||
| .option('-f, --functional', 'functional component') | ||
| .alias('g') | ||
| .description('Generate new file or store') | ||
| .action(() => { | ||
| require('../commands/generate'); | ||
| }); | ||
| (async () => { | ||
| registerHandlebarHelpers(); | ||
|
|
||
| program | ||
| .command('init <name>') | ||
| .alias('i') | ||
| .description('Create new boilerplate project') | ||
| .action(() => { | ||
| require('../commands/createNewProject'); | ||
| await cloneProjectTemplate(); | ||
|
|
||
| program | ||
| .version(require('../package').version, '-v, --version') | ||
| .command('generate <type> <name> ') | ||
| .option('-f, --functional', 'functional component') | ||
| .alias('g') | ||
| .description('Generate new file or store') | ||
| .action(() => { | ||
| require('../commands/generate'); | ||
| }); | ||
|
|
||
| program | ||
| .command('init <name>') | ||
| .alias('i') | ||
| .description('Create new boilerplate project') | ||
| .action(() => { | ||
| require('../commands/createNewProject'); | ||
| }); | ||
|
|
||
| program.on('command:*', () => { | ||
| console.log( | ||
| console.error( | ||
| 'Invalid command \nSee --help for a list of available commands.', | ||
| ), | ||
| ); | ||
| process.exit(1); | ||
| }); | ||
|
|
||
| program.on('command:*', () => { | ||
| console.log( | ||
|
|
||
| if (process.argv.length > 6) { | ||
| console.error( | ||
| 'Invalid command \nSee --help for a list of available commands.', | ||
| ), | ||
| ); | ||
| process.exit(1); | ||
| }); | ||
| 'Invalid command!\nSee --help for a list of available commands.', | ||
| ); | ||
| process.exit(1); | ||
| return; | ||
| } | ||
|
|
||
| if (process.argv.length > 6) { | ||
| console.error( | ||
| 'Invalid command!\nSee --help for a list of available commands.', | ||
| ); | ||
| process.exit(1); | ||
| return; | ||
| } | ||
| program.parse(process.argv); | ||
| program.parse(process.argv); | ||
| })(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,17 +8,22 @@ const render = require('consolidate').handlebars.render; | |
|
|
||
| const config = require('../config'); | ||
| const filesManager = require('../helpers/filesManager'); | ||
| const manageProjectConfig = require('../helpers/manageProjectConfig'); | ||
| const prettify = require('../helpers/prettify'); | ||
|
|
||
| const spinnerInstance = new Spinner('Installing dependencies... %s'); | ||
| spinnerInstance.setSpinnerString('|/-\\'); | ||
|
|
||
| const outputPath = program.args[0] | ||
| const packageSrc = `${outputPath}/package.json`; | ||
|
|
||
| const copyAssetsContent = async (includeCypress, middleware) => { | ||
| const projectTemplate = path.join(__dirname, '../packageTemplate'); | ||
| const projectTemplate = path.join(__dirname, '..', config.projectTemplateDir); | ||
|
|
||
| try { | ||
| console.info('Copying CEA files...'); | ||
|
|
||
| await fs.copy(projectTemplate, filesManager.getOutputFile(''), { | ||
| await fs.copy(projectTemplate, filesManager.getOutputFile(`/${outputPath}`), { | ||
| filter: path => (includeCypress ? true : !path.includes('cypress')), | ||
| }); | ||
|
|
||
|
|
@@ -37,31 +42,45 @@ const copyAssetsContent = async (includeCypress, middleware) => { | |
|
|
||
| const setMiddleware = async middleware => { | ||
| try { | ||
| const packagePath = filesManager.getOutputFile(`${outputPath}/package.json`); | ||
| const packageJson = JSON.parse( | ||
| fs.readFileSync(filesManager.getOutputFile('package.json')), | ||
| fs.readFileSync(packagePath), | ||
| ); | ||
|
|
||
| const middleWareDeps = { | ||
| const middlewareToRemove = { | ||
| package: middleware === config.supportedMiddlewares.reduxSaga ? 'redux-observable' : 'redux-saga', | ||
| file: middleware === config.supportedMiddlewares.reduxSaga ? config.projectFilesToOverride.rootEpic | ||
| : config.projectFilesToOverride.rootSaga, | ||
| files: middleware === config.supportedMiddlewares.reduxSaga ? | ||
| [ | ||
| config.projectFilesToOverride.rootEpic, | ||
| config.projectFilesToOverride.articlesEpic | ||
| ] : | ||
| [ | ||
| config.projectFilesToOverride.rootSaga, | ||
| config.projectFilesToOverride.articlesSaga | ||
| ], | ||
| }; | ||
|
|
||
| delete packageJson.dependencies[middleWareDeps.package]; | ||
|
|
||
| await exec( | ||
| ` | ||
| rm '${filesManager.getOutputFile(middleWareDeps.file)}' | ||
| `, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| delete packageJson.dependencies[middlewareToRemove.package]; | ||
|
|
||
| try { | ||
| for (let fileToRemove of middlewareToRemove.files) { | ||
| await exec( | ||
| ` | ||
| rm '${filesManager.getOutputFile(`/${outputPath}/${fileToRemove}`)}' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since you're removing all middleware related files, shouldn't we also remove |
||
| `, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| } | ||
| } catch({ stderr }) { | ||
| console.error(stderr); | ||
| } | ||
|
|
||
| await fillStoreConfig(middleware) | ||
|
|
||
| fs.writeFileSync( | ||
| filesManager.getOutputFile('package.json'), | ||
| packagePath, | ||
| JSON.stringify(packageJson, null, 2), | ||
| ); | ||
| } catch (err) { | ||
|
|
@@ -74,7 +93,7 @@ const setMiddleware = async middleware => { | |
| const removeCypressFromPackage = async () => { | ||
| try { | ||
| const packageJson = JSON.parse( | ||
| fs.readFileSync(filesManager.getOutputFile('package.json')), | ||
| fs.readFileSync(filesManager.getOutputFile(packageSrc)), | ||
| ); | ||
|
|
||
| const scripts = ['cy:ci', 'cy:open', 'cy:run']; | ||
|
|
@@ -86,7 +105,7 @@ const removeCypressFromPackage = async () => { | |
| delete packageJson.devDependencies['cypress']; | ||
|
|
||
| fs.writeFileSync( | ||
| filesManager.getOutputFile('package.json'), | ||
| filesManager.getOutputFile(packageSrc), | ||
| JSON.stringify(packageJson, null, 2), | ||
| ); | ||
| } catch (err) { | ||
|
|
@@ -98,18 +117,20 @@ const removeCypressFromPackage = async () => { | |
| }; | ||
|
|
||
| const fillStoreConfig = async middleware => { | ||
| const storeConfigSrc = filesManager.getOutputFile(config.projectFilesToOverride.storeConfig); | ||
| const storeConfigSrc = filesManager.getOutputFile(`/${outputPath}/${config.projectFilesToOverride.storeConfig}`); | ||
| const storeConfigTemplateFile = fs.readFileSync(filesManager.getTemplateFile('/store/storeConfig.ts')); | ||
| if (!storeConfigTemplateFile) { | ||
| console.error('Could not find store config template!'); | ||
| return; | ||
| } | ||
|
|
||
| try { | ||
| const res = await render(storeConfigTemplateFile.toString(), { | ||
| middleware, | ||
| supportedMiddlewares: config.supportedMiddlewares | ||
| }); | ||
| const res = prettify( | ||
| await render(storeConfigTemplateFile.toString(), { | ||
| middleware, | ||
| supportedMiddlewares: config.supportedMiddlewares | ||
| }) | ||
| ); | ||
| fs.writeFileSync(storeConfigSrc, res); | ||
| console.info('Successfuly updated store config file: ' + storeConfigSrc); | ||
| } catch(e) { | ||
|
|
@@ -121,16 +142,58 @@ const fillStoreConfig = async middleware => { | |
|
|
||
| const init = async (includeCypress, packageManager, middleware) => { | ||
| await copyAssetsContent(includeCypress, middleware); | ||
| spinnerInstance.start(); | ||
| await exec( | ||
| `cd ${program.args[0]} && ${packageManager.toLowerCase()} install`, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
|
|
||
| console.info('Setup finished!'); | ||
| }, | ||
| ); | ||
| spinnerInstance.stop(); | ||
|
|
||
| await manageProjectConfig.generateConfig({ | ||
| selectedMiddleware: middleware | ||
| }, outputPath); | ||
|
|
||
| try { | ||
| await exec( | ||
| `cd ./${program.args[0]} && git init`, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
|
|
||
| spinnerInstance.start(); | ||
| await exec( | ||
| `cd ${program.args[0]} && ${packageManager.toLowerCase()} install`, | ||
| (err, stdout) => { | ||
| console.log(err); | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| spinnerInstance.stop(); | ||
| console.log(''); | ||
| console.info('Setup finished!'); | ||
|
|
||
| await exec( | ||
| `cd ./${program.args[0]} && git add --ignore-errors .`, | ||
| (err, stdout) => { | ||
| console.log(err); | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| } catch({ stdout, stderr }) { | ||
| stdout && stdout !== '' && console.error(stdout); | ||
| stderr && stderr !== '' && console.error(stderr); | ||
| } | ||
|
|
||
| try { | ||
| await exec( | ||
| `cd ./${program.args[0]} && git commit -m "Initial commit from Create Espeo React App CLI"`, | ||
| (err, stdout) => { | ||
| console.log(err); | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| } catch({ stdout, stderr }) { | ||
| stdout && stdout !== '' && console.error(stdout); | ||
| stderr && stderr !== '' && console.error(stderr); | ||
| } | ||
|
|
||
| console.info('Latest changes committed!'); | ||
|
|
||
| }; | ||
|
|
||
| inquirer.prompt(config.questions).then(async answers => { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,8 +33,13 @@ module.exports = { | |
| projectFilesToOverride: { | ||
| rootEpic: 'src/app/store/rootEpic.ts', | ||
| rootSaga: 'src/app/store/rootSaga.ts', | ||
| articlesEpic: 'src/app/pages/MainArticles/store/epics/index.ts', | ||
| articlesSaga: 'src/app/pages/MainArticles/store/saga/index.ts', | ||
| storeConfig: 'src/app/store/index.ts', | ||
| package: 'package.json', | ||
| }, | ||
| templatesFolder: '/templates' | ||
| templatesFolder: '/templates', | ||
| projectTemplateRepositoryUrl: 'https://github.com/espeo/espeo-create-react-app.git', | ||
| projectTemplateVersion: '1.0.0', | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. would it be possible to have this value read dynamically from package.json file from cloned repository, instead of keeping it hardcoded? |
||
| projectTemplateDir: './templates/projectTemplate', | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| const path = require('path'); | ||
| const fs = require('fs'); | ||
| const exec = require('await-exec'); | ||
|
|
||
| const config = require('../config'); | ||
|
|
||
| const projectTemplateSrc = path.join(__dirname, '..', config.projectTemplateDir); | ||
|
|
||
| const cloneProjectTemplate = async () => { | ||
| if (!fs.existsSync(projectTemplateSrc)) { | ||
| try { | ||
| await exec( | ||
| ` | ||
| git clone ${config.projectTemplateRepositoryUrl} --branch ${config.projectTemplateVersion} ${projectTemplateSrc} | ||
| `, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
|
|
||
| await exec( | ||
| ` | ||
| rm -R ${projectTemplateSrc}/.git | ||
| `, | ||
| (err, stdout) => { | ||
| console.log(stdout); | ||
| }, | ||
| ); | ||
| } catch(err) { | ||
| console.error(err); | ||
| } | ||
|
|
||
| console.log('Successfully cloned template repository'); | ||
| return | ||
| } | ||
| } | ||
|
|
||
| module.exports=cloneProjectTemplate; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,22 @@ | ||
| const path = require('path'); | ||
| const program = require('commander'); | ||
| const find = require('find'); | ||
|
|
||
| const config = require('../config'); | ||
| const maxDirectoryDepth = 10; | ||
|
|
||
| let dirDepth = 0; | ||
| const findFile = (fileName, root) => { | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. isn't this function of yours doing exactly the same what |
||
| let files = find.fileSync(fileName, root || process.cwd()); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't it be |
||
| if (dirDepth < maxDirectoryDepth && files.length === 0) { | ||
| dirDepth++; | ||
| return findFile(fileName, '../'.repeat(dirDepth)); | ||
| } | ||
| dirDepth = 0; | ||
| return files[0]; | ||
| } | ||
|
|
||
| module.exports = { | ||
| getTemplateFile: templateSrc => path.join(__dirname, '..', config.templatesFolder, templateSrc), | ||
| getOutputFile: outputSrc => path.join(process.cwd(), program.args[0], outputSrc) | ||
| getOutputFile: outputSrc => path.join(process.cwd(), outputSrc), | ||
| findFile | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing semicolon