@clea/cli
Version:
CLI tool for AngularJS & Typescript projects
215 lines (179 loc) • 6.66 kB
JavaScript
const ejs = require('ejs'),
fs = require('fs-extra'),
glob = require('glob'),
slugify = require('slugify'),
chalk = require('chalk'),
os = require('os'),
Spinner = require('cli-spinner').Spinner,
Project = require('../project'),
ChildProcess = require('../utilities/child-process.utils'),
DynamicPathParser = require('../utilities/dynamic-path-parser'),
logger = require('../../vendors/logger');
class InitProject {
/**
* Instantiate a new InitProject
*
* @param {string} name Application name
* @param {string} type Application type
* @param {Object} options Generator options
*/
constructor (name, type, options) {
this.name = name;
this.type = type;
this.options = options;
this.normalizedName = slugify(name);
this.projectPath = (options.init) ? './' : `./${this.normalizedName}`;
if (type === Project.TYPE.LIBRARY) {
throw new Error(`${chalk.blue('--lib')} option has been deactivated for now. It's under active development`);
}
}
createFolder () {
try {
fs.mkdirSync(this.projectPath);
} catch (err) {
throw new Error(`Directory "${this.normalizedName}" already exists`);
}
}
start () {
this._log(`installing '${this.name}'`);
let excludedFiles = [];
// To copy only if `--ui-framework=material`
if (this.options.uiFramework !== 'material') {
excludedFiles = excludedFiles.concat([
'src/styles/vendors/__angular-material.scss'
]);
}
// To copy only if `--ui-framework=bootstrap`
if (this.options.uiFramework !== 'bootstrap') {
excludedFiles = excludedFiles.concat([
'src/styles/vendors/__angular-ui-bootstrap.scss'
]);
}
// To copy only if `--make-it-progressive` option has been used
if (!this.options.makeItProgressive) {
excludedFiles = excludedFiles.concat([
'sw.conf.js',
'src/app/app.sw.ts',
'src/public/service-worker.js'
]);
}
return this.copyStaticFiles(excludedFiles)
.then(() => this.copyFiles({
appName : this.name,
slugifiedName: slugify(this.name),
ngMaterial : this.options.uiFramework === 'material',
bootstrap : this.options.uiFramework === 'bootstrap',
pwa : this.options.makeItProgressive,
commitMessageConventions : this.options.commitMessageConventions
}, excludedFiles))
.then(() => (this.options.skipGit) ? Promise.resolve() : this.initializeGit())
.then(() => (this.options.skipInstall) ? Promise.resolve() : this.installDependencies())
.then(() => this._log(`${os.EOL}Project '${this.name}' successfully created.`, 'info'));
}
copyStaticFiles (excludedFiles = []) {
let templatePath = `${__dirname}/../../templates/${this.type}/`;
return new Promise((resolve, reject) => {
glob(`${templatePath}/**/!(_*)`, (err, files) => {
if (err) {
reject(err);
} else {
for (let file of files) {
const relativeFilePath = DynamicPathParser.relative(templatePath, file);
if (!excludedFiles.includes(relativeFilePath)) {
if (fs.lstatSync(file).isDirectory()) {
if (!fs.existsSync(`${this.projectPath}/${relativeFilePath}`)) {
fs.mkdirSync(`${this.projectPath}/${relativeFilePath}`);
}
} else {
let exists = fs.existsSync(`${this.projectPath}/${relativeFilePath}`);
if (!exists) {
fs.copySync(file, `${this.projectPath}/${relativeFilePath}`);
}
this._log(` ${exists ? chalk.yellow('IDENTICAL') : chalk.green('CREATE')} ${relativeFilePath}`);
}
}
}
resolve();
}
});
});
}
copyFiles (data, excludedFiles = []) {
let templatePath = `${__dirname}/../../templates/${this.type}/`;
return new Promise((resolve, reject) => {
glob(`${templatePath}/**/_*`, (err, files) => {
if (err) {
reject(err);
} else {
for (let file of files) {
let relativeFilePath = DynamicPathParser.relative(templatePath, file),
targetFile = relativeFilePath.replace(/(.*?)_([^/]*)/, (m, p1, p2) => `${p1}${p2}`);
if (!excludedFiles.includes(relativeFilePath)) {
if (!fs.lstatSync(file).isDirectory()) {
let templateString = fs.readFileSync(file, 'utf-8');
let renderedString = ejs.render(templateString, data).replace(/<--%/g, '<%').replace(/%-->/g, '%>');
let exists = fs.existsSync(`${this.projectPath}/${targetFile}`);
if (!exists) {
fs.writeFileSync(`${this.projectPath}/${targetFile}`, renderedString);
}
this._log(` ${exists ? chalk.yellow('IDENTICAL') : chalk.green('CREATE')} ${targetFile}`);
}
}
}
resolve();
}
});
});
}
initializeGit () {
const opts = {
stdio: (this.options.verbose) ? 'inherit' : 'pipe',
cwd : this.projectPath,
shell: true
};
return ChildProcess.spawn('git', [ 'init' ], opts)
.then(() => ChildProcess.spawn('git', [ 'add .' ], opts))
.then(() => ChildProcess.spawn('git', [ 'commit -m "first commit"'], Object.assign(opts, {
stdio: 'pipe'
})))
.then(() => this._log('Successfully initialized git.', 'info'));
}
installDependencies () {
return new Promise((resolve, reject) => {
this._log(`Installing packages for tooling via NPM.`, 'info');
let spinner = new Spinner('installing');
spinner.setSpinnerString(18);
if (!this.options.verbose) {
spinner.start();
}
return ChildProcess.spawn('npm', [ 'install' ], {
stdio: (this.options.verbose) ? 'inherit' : 'pipe',
cwd : this.projectPath,
shell: true
}).then((code) => {
if (code > 0) {
reject('Dependencies installation failed, try to use --verbose flag to see more details');
}
if (spinner.isSpinning()) {
spinner.stop();
}
return true;
});
});
}
_log (message, type = 'pop') {
if (!this.options.quiet) {
switch (type) {
case 'info':
logger.info(message);
break;
case 'pop':
default:
logger.pop(message);
break;
}
}
}
}
InitProject.UI_FRAMEWORKS = ['bootstrap', 'material', undefined];
module.exports = InitProject;