generator-apparena-app-builder
Version:
Generate App-Arena React App
483 lines (431 loc) • 14.3 kB
JavaScript
'use strict';
/* eslint-disable arrow-parens */
var generators = require('yeoman-generator');
var chalk = require('chalk');
var yosay = require('yosay');
var path = require('path');
var _ = require('lodash');
var extend = _.merge;
var parseAuthor = require('parse-author');
var githubUsername = require('github-username');
var getAppArenaComponent = require('./helpers/apparena');
const ExpressJS = 'ExpressJS';
const HapiJS = 'HapiJS';
const KoaJS = 'KoaJS';
module.exports = generators.Base.extend({
constructor: function () {
generators.Base.apply(this, arguments);
this.option('travis', {
type: Boolean,
required: false,
defaults: true,
desc: 'Include travis config'
});
this.option('license', {
type: Boolean,
required: false,
defaults: true,
desc: 'Include a license'
});
this.option('name', {
type: String,
required: false,
desc: 'Project name'
});
this.option('githubAccount', {
type: String,
required: false,
desc: 'GitHub username or organization'
});
this.option('projectRoot', {
type: String,
required: false,
defaults: 'server',
desc: 'Relative path to the project code root'
});
this.option('readme', {
type: String,
required: false,
desc: 'Content to insert in the README.md file'
});
},
initializing: function () {
this.pkg = this.fs.readJSON(this.destinationPath('package.json'), {});
if (this.pkg.keywords) {
this.pkg.keywords = this.pkg.keywords.filter((x) => x);
}
// Pre set the default props from the information we have at this point
this.props = {
name: this.pkg.name,
description: this.pkg.description,
version: this.pkg.version,
homepage: this.pkg.homepage
};
if (_.isObject(this.pkg.author)) {
this.props.authorName = this.pkg.author.name;
this.props.authorEmail = this.pkg.author.email;
this.props.authorUrl = this.pkg.author.url;
this.props.createDirectory = false;
this.props.serverType = this.fs.exists(this.destinationPath('src/server/express-server.js')) ? ExpressJS :
this.fs.exists(this.destinationPath('src/server/koa-server.js')) ? KoaJS : HapiJS;
this.props.pwa = this.fs.exists(this.destinationPath('client/sw-registration.js'));
this.props.autoSsr = this.fs.exists(this.destinationPath('server/plugins/autossr.js'));
} else if (_.isString(this.pkg.author)) {
var info = parseAuthor(this.pkg.author);
this.props.authorName = info.name;
this.props.authorEmail = info.email;
this.props.authorUrl = info.url;
}
},
prompting: {
greeting: function () {
this.log(yosay(
'Welcome to the phenomenal ' + chalk.red('Electrode App') + ' generator!'
));
},
askFor: function () {
if (this.pkg.name || this.options.name) {
this.props.name = this.pkg.name || _.kebabCase(this.options.name);
}
var prompts = [
{
type: "input",
name: 'name',
message: 'Application Name',
when: !this.props.name,
default: path.basename(process.cwd())
},
{
type: "input",
name: 'description',
message: 'Description',
when: !this.props.description
},
{
type: "input",
name: 'homepage',
message: 'Project homepage url',
when: !this.props.homepage
},
{
type: 'list',
name: 'serverType',
message: 'Which framework for the server?',
when: !this.props.serverType,
choices: [HapiJS, ExpressJS, KoaJS],
default: HapiJS
},
{
type: "input",
name: 'authorName',
message: 'Author\'s Name',
when: !this.props.authorName,
default: this.user.git.name(),
store: true
},
{
type: "input",
name: 'authorEmail',
message: 'Author\'s Email',
when: !this.props.authorEmail,
default: this.user.git.email(),
store: true
},
{
type: "input",
name: 'authorUrl',
message: 'Author\'s Homepage',
when: !this.props.authorUrl,
store: true
},
{
type: "input",
name: 'keywords',
message: 'Package keywords (comma to split)',
when: _.isEmpty(this.pkg.keywords),
filter: function (words) {
return words.split(/\s*,\s*/g).filter((x) => x);
}
},
{
type: "confirm",
name: "pwa",
message: "Would you like to make a Progressive Web App?",
when: this.props.pwa === undefined,
default: false
},
{
type: "confirm",
name: "autoSsr",
message: "Disable server side rendering based on high load?",
when: this.props.autoSsr === undefined,
default: false
},
{
type: "confirm",
name: "createDirectory",
message: "Would you like to create a new directory for your project?",
when: this.props.createDirectory === undefined,
default: true
}
];
return this.prompt(prompts).then((props) => {
this.props = extend(this.props, props);
if (this.props.createDirectory) {
var newRoot = this.destinationPath() + '/' + _.kebabCase(_.deburr(this.props.name));
this.destinationRoot(newRoot);
}
// saving to storage after the correct destination root is set
this.config.set('serverType', this.props.serverType);
});
},
askForAppArenaAccount: function () {
var prompts = [
{
type: "input",
name: 'projectId',
message: 'App-Arena Project Id',
when: !this.props.projectId
},
{
type: "input",
name: 'aaApiKey',
message: 'App-Arena Api-Key',
when: !this.props.aaApiKey
}
];
return this.prompt(prompts).then((props) => {
this.props = extend(this.props, props);
// saving to storage after the correct destination root is set
this.config.set('projectId', this.props.projectId);
});
},
askForAppArenaComponents: function () {
var done = this.async();
getAppArenaComponent("", (err, choices) => {
this.prompt({
name: 'apparenaComponents',
type: 'checkbox',
message: 'Select the Components you want to install',
choices: choices
}).then((prompt) => {
this.props.apparenaComponents = prompt;
done();
});
});
},
askForGithubAccount: function () {
if (this.options.githubAccount) {
this.props.githubAccount = this.options.githubAccount;
return;
}
var done = this.async();
githubUsername(this.props.authorEmail, (err, username) => {
if (err) {
username = username || '';
}
this.prompt({
name: 'githubAccount',
message: 'GitHub username or organization',
default: username
}).then((prompt) => {
this.props.githubAccount = prompt.githubAccount;
done();
});
});
}
},
writing: function () {
const isHapi = this.config.get('serverType') === HapiJS;
const isExpress = this.config.get('serverType') === ExpressJS;
const isPWA = this.props.pwa;
const isAutoSSR = this.props.autoSsr;
let ignoreArray = [];
if (isHapi) {
ignoreArray.push('**/src/server/express-server.js');
ignoreArray.push('**/src/server/koa-server.js');
} else if (isExpress) {
ignoreArray.push('**/src/server/koa-server.js');
} else {
ignoreArray.push('**/src/server/express-server.js');
}
// Re-read the content at this point because a composed generator might modify it.
var currentPkg = this.fs.readJSON(this.destinationPath('package.json'), {});
const _pkg = '_package.json';
this.fs.copyTpl(
this.templatePath(_pkg),
this.destinationPath(_pkg),
{isHapi, isExpress, isPWA, isAutoSSR}
);
var defaultPkg = this.fs.readJSON(this.destinationPath(_pkg));
this.fs.delete(this.destinationPath(_pkg));
['name', 'version', 'description', 'homepage', 'main', 'license'].forEach((x) => {
currentPkg[x] = currentPkg[x] || undefined;
});
var updatePkg = _.defaultsDeep(currentPkg, {
name: _.kebabCase(this.props.name),
version: '0.0.1',
description: this.props.description,
homepage: this.props.homepage,
author: {
name: this.props.authorName,
email: this.props.authorEmail,
url: this.props.authorUrl
},
files: [
this.options.projectRoot
],
dependencies: {},
main: path.join(
this.options.projectRoot,
'index.js'
).replace(/\\/g, '/'),
keywords: []
});
console.log(this.props.apparenaComponents);
this.props.apparenaComponents.forEach((components) => {
updatePkg.dependencies[components.name] = components.version;
});
var pkg = extend({}, defaultPkg, updatePkg);
// Combine the keywords
if (this.props.keywords) {
pkg.keywords = _.uniq(this.props.keywords.concat(pkg.keywords)).filter((x) => x);
}
const sortDep = (dep) => {
if (typeof pkg[dep] === "object") {
pkg[dep] = _.pick(pkg[dep], Object.keys(pkg[dep]).sort());
}
};
["dependencies", "devDependencies", "peerDependencies", "optionalDependencies"].forEach(sortDep);
// Let's extend package.json so we're not overwriting user previous fields
this.fs.writeJSON(this.destinationPath('package.json'), pkg);
['gulpfile.js', 'config', 'test'].forEach((f) => {
this.fs.copy(
this.templatePath(f),
this.destinationPath(f)
);
});
//special handling for the server file
this.fs.copyTpl(
this.templatePath('src/server'),
this.destinationPath('src/server'),
{isHapi, isExpress},
{},
{
globOptions: {
ignore: ignoreArray
}
}
);
this.fs.copyTpl(
this.templatePath('src/client'),
this.destinationPath('src/client'),
{pwa: isPWA},
{}, // template options
{ // copy options
globOptions: {
// Images are damaged by the template compiler
ignore: ['**/client/images/**', !isPWA && '**/client/sw-registration.js' || '']
}
}
);
['src/client', 'src/server', 'test/client', 'test/server'].forEach((d) => {
this.fs.move(this.destinationPath(d + '/babelrc'), this.destinationPath(d + '/.babelrc'));
});
this.fs.copy(
this.templatePath('src/client/images'),
this.destinationPath('src/client/images')
);
},
default: function () {
if (this.options.travis) {
this.composeWith('travis', {}, {
local: require.resolve('generator-travis/generators/app')
});
}
this.composeWith('apparena-app-builder:editorconfig', {}, {
local: require.resolve('../editorconfig')
});
this.composeWith('apparena-app-builder:git', {
options: {
name: this.props.name,
githubAccount: this.props.githubAccount
}
}, {
local: require.resolve('../git')
});
if (this.options.license && !this.pkg.license) {
this.composeWith('license', {
options: {
name: this.props.authorName,
email: this.props.authorEmail,
website: this.props.authorUrl
}
}, {
local: require.resolve('generator-license/app')
});
}
if (this.props.projectId && this.props.aaApiKey) {
this.composeWith('apparena-app-builder:env', {
options: {
aaApiKey: this.props.aaApiKey,
projectId: this.props.projectId
}
}, {
local: require.resolve('../env')
});
}
if (!this.fs.exists(this.destinationPath('README.md'))) {
this.composeWith('apparena-app-builder:readme', {
options: {
name: this.props.name,
description: this.props.description,
githubAccount: this.props.githubAccount,
authorName: this.props.authorName,
authorUrl: this.props.authorUrl,
content: this.options.readme
}
}, {
local: require.resolve('../readme')
});
}
if (!this.fs.exists(this.destinationPath('config/default.js'))) {
this.composeWith('apparena-app-builder:config', {
options: {
name: this.props.name,
pwa: this.props.pwa,
serverType: this.props.serverType,
isAutoSsr: this.props.autoSsr
}
}, {
local: require.resolve('../config')
});
}
if (!this.fs.exists(this.destinationPath('server/plugins/webapp'))) {
this.composeWith('apparena-app-builder:webapp', {
options: {
pwa: this.props.pwa,
isAutoSsr: this.props.autoSsr
}
}, {
local: require.resolve('../webapp')
});
}
},
install: function () {
this.installDependencies({
bower: false,
npm: true,
yarn: true
});
},
end: function () {
var chdir = this.props.createDirectory ? "'cd " + _.kebabCase(_.deburr(this.props.name)) + "' then " : "";
this.log(
"\n" + chalk.green.underline("Your new Electrode application is ready!") +
"\n" +
"\nType " + chdir + "'gulp dev' to start the server." +
"\n"
);
}
});